revision-id: 083279f7838d45c475344d20585ead72a147a21d (mariadb-10.3.7-52-g083279f7838) parent(s): 0121d5a790983c08dabedc66e70f862e47f7c8c7 6b8802e8dd5467556a024d807a1df23940b00895 author: Oleksandr Byelkin committer: Oleksandr Byelkin timestamp: 2018-06-19 14:51:50 +0200 message: Merge commit '6b8802e8dd5467556a024d807a1df23940b00895' into bb-10.3-fix_len_dec mysql-test/main/alter_table.result | 11 +++ mysql-test/main/alter_table.test | 16 ++++ sql/item.h | 2 +- sql/item_cmpfunc.cc | 98 +++++++++++-------- sql/item_cmpfunc.h | 82 +++++++++------- sql/item_func.cc | 143 ++++++++++++++------------- sql/item_func.h | 159 +++++++++++++++++------------- sql/item_geofunc.cc | 9 +- sql/item_geofunc.h | 77 ++++++++------- sql/item_inetfunc.h | 12 ++- sql/item_jsonfunc.cc | 57 +++++++---- sql/item_jsonfunc.h | 40 ++++---- sql/item_strfunc.cc | 164 +++++++++++++++++++------------ sql/item_strfunc.h | 192 ++++++++++++++++++++++--------------- sql/item_subselect.cc | 71 +++++++++----- sql/item_subselect.h | 22 ++--- sql/item_sum.cc | 50 +++++----- sql/item_sum.h | 34 ++++--- sql/item_timefunc.cc | 38 +++++--- sql/item_timefunc.h | 146 ++++++++++++++++------------ sql/item_vers.h | 8 +- sql/item_windowfunc.cc | 6 +- sql/item_windowfunc.h | 15 ++- sql/item_xmlfunc.cc | 13 +-- sql/item_xmlfunc.h | 2 +- sql/sql_select.cc | 3 +- sql/sql_table.cc | 14 ++- 27 files changed, 892 insertions(+), 592 deletions(-) diff --cc mysql-test/main/alter_table.result index cb5553a086c,00000000000..ac6f9aba17b mode 100644,000000..100644 --- a/mysql-test/main/alter_table.result +++ b/mysql-test/main/alter_table.result @@@ -1,2384 -1,0 +1,2395 @@@ +drop table if exists t1,t2; +drop database if exists mysqltest; +create table t1 ( +col1 int not null auto_increment primary key, +col2 varchar(30) not null, +col3 varchar (20) not null, +col4 varchar(4) not null, +col5 enum('PENDING', 'ACTIVE', 'DISABLED') not null, +col6 int not null, to_be_deleted int); +insert into t1 values (2,4,3,5,"PENDING",1,7); +alter table t1 +add column col4_5 varchar(20) not null after col4, +add column col7 varchar(30) not null after col5, +add column col8 datetime not null, drop column to_be_deleted, +change column col2 fourth varchar(30) not null after col3, +modify column col6 int not null first; +select * from t1; +col6 col1 col3 fourth col4 col4_5 col5 col7 col8 +1 2 3 4 5 PENDING 0000-00-00 00:00:00 +drop table t1; +create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); +insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); +alter table t1 add column new_col int, order by payoutid,bandid; +select * from t1; +bandID payoutID new_col +6 1 NULL +3 4 NULL +1 6 NULL +2 6 NULL +4 9 NULL +5 10 NULL +7 12 NULL +8 12 NULL +alter table t1 order by bandid,payoutid; +select * from t1; +bandID payoutID new_col +1 6 NULL +2 6 NULL +3 4 NULL +4 9 NULL +5 10 NULL +6 1 NULL +7 12 NULL +8 12 NULL +drop table t1; +CREATE TABLE t1 ( +GROUP_ID int(10) unsigned DEFAULT '0' NOT NULL, +LANG_ID smallint(5) unsigned DEFAULT '0' NOT NULL, +NAME varchar(80) DEFAULT '' NOT NULL, +PRIMARY KEY (GROUP_ID,LANG_ID), +KEY NAME (NAME)); +ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null; +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +GROUP_ID int(10) unsigned NULL NO PRI 0 # +LANG_ID smallint(5) unsigned NULL NO PRI 0 # +NAME char(80) latin1_swedish_ci NO MUL NULL # +DROP TABLE t1; +create table t1 (n int); +insert into t1 values(9),(3),(12),(10); +alter table t1 order by n; +select * from t1; +n +3 +9 +10 +12 +drop table t1; +CREATE TABLE t1 ( +id int(11) unsigned NOT NULL default '0', +category_id tinyint(4) unsigned NOT NULL default '0', +type_id tinyint(4) unsigned NOT NULL default '0', +body text NOT NULL, +user_id int(11) unsigned NOT NULL default '0', +status enum('new','old') NOT NULL default 'new', +PRIMARY KEY (id) +) ENGINE=MyISAM; +ALTER TABLE t1 ORDER BY t1.id, t1.status, t1.type_id, t1.user_id, t1.body; +DROP TABLE t1; +CREATE TABLE t1 (AnamneseId int(10) unsigned NOT NULL auto_increment,B BLOB,PRIMARY KEY (AnamneseId)) engine=myisam; +insert into t1 values (null,"hello"); +LOCK TABLES t1 WRITE; +ALTER TABLE t1 ADD Column new_col int not null; +UNLOCK TABLES; +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +DROP TABLE t1; +create table t1 (i int unsigned not null auto_increment primary key); +insert into t1 values (null),(null),(null),(null); +alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i); +select * from t1; +i +1 +2 +3 +4 +drop table t1; +create table t1 (name char(15)); +insert into t1 (name) values ("current"); +create database mysqltest; +create table mysqltest.t1 (name char(15)); +insert into mysqltest.t1 (name) values ("mysqltest"); +select * from t1; +name +current +select * from mysqltest.t1; +name +mysqltest +alter table t1 rename mysqltest.t1; +ERROR 42S01: Table 't1' already exists +select * from t1; +name +current +select * from mysqltest.t1; +name +mysqltest +drop table t1; +drop database mysqltest; +create table t1 (n1 int not null, n2 int, n3 int, n4 float, +unique(n1), +key (n1, n2, n3, n4), +key (n2, n3, n4, n1), +key (n3, n4, n1, n2), +key (n4, n1, n2, n3) ); +alter table t1 disable keys; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 n1 1 n1 A 0 NULL NULL BTREE +t1 1 n1_2 1 n1 A NULL NULL NULL BTREE disabled +t1 1 n1_2 2 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n1_2 3 n3 A NULL NULL NULL YES BTREE disabled +t1 1 n1_2 4 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n2 1 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n2 2 n3 A NULL NULL NULL YES BTREE disabled +t1 1 n2 3 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n2 4 n1 A NULL NULL NULL BTREE disabled +t1 1 n3 1 n3 A NULL NULL NULL YES BTREE disabled +t1 1 n3 2 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n3 3 n1 A NULL NULL NULL BTREE disabled +t1 1 n3 4 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n4 1 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n4 2 n1 A NULL NULL NULL BTREE disabled +t1 1 n4 3 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n4 4 n3 A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 n1 1 n1 A 10 NULL NULL BTREE +t1 1 n1_2 1 n1 A 10 NULL NULL BTREE +t1 1 n1_2 2 n2 A 10 NULL NULL YES BTREE +t1 1 n1_2 3 n3 A 10 NULL NULL YES BTREE +t1 1 n1_2 4 n4 A 10 NULL NULL YES BTREE +t1 1 n2 1 n2 A 10 NULL NULL YES BTREE +t1 1 n2 2 n3 A 10 NULL NULL YES BTREE +t1 1 n2 3 n4 A 10 NULL NULL YES BTREE +t1 1 n2 4 n1 A 10 NULL NULL BTREE +t1 1 n3 1 n3 A 10 NULL NULL YES BTREE +t1 1 n3 2 n4 A 10 NULL NULL YES BTREE +t1 1 n3 3 n1 A 10 NULL NULL BTREE +t1 1 n3 4 n2 A 10 NULL NULL YES BTREE +t1 1 n4 1 n4 A 10 NULL NULL YES BTREE +t1 1 n4 2 n1 A 10 NULL NULL BTREE +t1 1 n4 3 n2 A 10 NULL NULL YES BTREE +t1 1 n4 4 n3 A 10 NULL NULL YES BTREE +drop table t1; +create table t1 (i int unsigned not null auto_increment primary key); +alter table t1 rename t2; +alter table t2 rename t1, add c char(10) comment "no comment"; +show columns from t1; +Field Type Null Key Default Extra +i int(10) unsigned NO PRI NULL auto_increment +c char(10) YES NULL +drop table t1; +create table t1 (a int, b int); +alter table t1 add unique (a,b), add key (b); +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A 3 NULL NULL YES BTREE +t1 0 a 2 b A 300 NULL NULL YES BTREE +t1 1 b 1 b A 100 NULL NULL YES BTREE +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status Table is already up to date +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A 3 NULL NULL YES BTREE +t1 0 a 2 b A 300 NULL NULL YES BTREE +t1 1 b 1 b A 100 NULL NULL YES BTREE +drop table t1; +CREATE TABLE t1 (i int(10), index(i) ) ENGINE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +INSERT DELAYED INTO t1 VALUES(1),(2),(3); +ALTER TABLE t1 ENABLE KEYS; +drop table t1; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User) +) ENGINE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty'); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; +CHECK TABLES t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User), +KEY (Host) +) ENGINE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''); +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +ALTER TABLE t1 ENABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 2 NULL NULL BTREE +t1 1 Host 1 Host A 1 NULL NULL BTREE +UNLOCK TABLES; +CHECK TABLES t1; +Table Op Msg_type Msg_text +test.t1 check status OK +LOCK TABLES t1 WRITE; +ALTER TABLE t1 RENAME t2; +UNLOCK TABLES; +select * from t2; +Host User +localhost +localhost root +DROP TABLE t2; +CREATE TABLE t1 ( +Host varchar(16) binary NOT NULL default '', +User varchar(16) binary NOT NULL default '', +PRIMARY KEY (Host,User), +KEY (Host) +) ENGINE=MyISAM; +LOCK TABLES t1 WRITE; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 Host A NULL NULL NULL BTREE +t1 0 PRIMARY 2 User A 0 NULL NULL BTREE +t1 1 Host 1 Host A NULL NULL NULL BTREE disabled +DROP TABLE t1; +create table t1 (a int); +alter table t1 rename to ``; +ERROR 42000: Incorrect table name '' +rename table t1 to ``; +ERROR 42000: Incorrect table name '' +drop table t1; +drop table if exists t1, t2; +Warnings: +Note 1051 Unknown table 'test.t1' +Note 1051 Unknown table 'test.t2' +create table t1 ( a varchar(10) not null primary key ) engine=myisam; +create table t2 ( a varchar(10) not null primary key ) engine=merge union=(t1); +flush tables; +alter table t1 modify a varchar(10); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(10) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`) +flush tables; +alter table t1 modify a varchar(10) not null; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` varchar(10) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t1`) +drop table if exists t1, t2; +create table t1 (a int, b int, c int, d int, e int, f int, g int, h int,i int, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert ignore into t1 (a) values(1); +Warnings: +Warning 1364 Field 'b' doesn't have a default value +Warning 1364 Field 'c' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'e' doesn't have a default value +Warning 1364 Field 'f' doesn't have a default value +Warning 1364 Field 'g' doesn't have a default value +Warning 1364 Field 'h' doesn't have a default value +Warning 1364 Field 'i' doesn't have a default value +show table status like 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary +t1 MyISAM 10 Fixed 1 37 X X X X X X X X latin1_swedish_ci NULL X N +alter table t1 modify a int; +show table status like 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary +t1 MyISAM 10 Fixed 1 37 X X X X X X X X latin1_swedish_ci NULL X N +drop table t1; +create table t1 (a int not null, b int not null, c int not null, d int not null, e int not null, f int not null, g int not null, h int not null,i int not null, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert ignore into t1 (a) values(1); +Warnings: +Warning 1364 Field 'b' doesn't have a default value +Warning 1364 Field 'c' doesn't have a default value +Warning 1364 Field 'd' doesn't have a default value +Warning 1364 Field 'e' doesn't have a default value +Warning 1364 Field 'f' doesn't have a default value +Warning 1364 Field 'g' doesn't have a default value +Warning 1364 Field 'h' doesn't have a default value +Warning 1364 Field 'i' doesn't have a default value +show table status like 't1'; +Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary +t1 MyISAM 10 Fixed 1 37 X X X X X X X X latin1_swedish_ci NULL X N +drop table t1; +set names koi8r; +create table t1 (a char(10) character set koi8r); +insert into t1 values ('����'); +select a,hex(a) from t1; +a hex(a) +���� D4C5D3D4 +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +���� F2E5F1F2 +alter table t1 change a a binary(4); +select a,hex(a) from t1; +a hex(a) +���� F2E5F1F2 +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +���� F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +���� D4C5D3D4 +alter table t1 change a a varchar(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +���� F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +���� D4C5D3D4 +alter table t1 change a a text character set cp1251; +select a,hex(a) from t1; +a hex(a) +���� F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +���� D4C5D3D4 +delete from t1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) CHARACTER SET koi8r DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 DEFAULT CHARACTER SET latin1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) CHARACTER SET koi8r DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 CONVERT TO CHARACTER SET latin1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 DEFAULT CHARACTER SET cp1251; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) CHARACTER SET latin1 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=cp1251 +drop table t1; +create table t1 (myblob longblob,mytext longtext) +default charset latin1 collate latin1_general_cs; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `myblob` longblob DEFAULT NULL, + `mytext` longtext COLLATE latin1_general_cs DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs +alter table t1 character set latin2; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `myblob` longblob DEFAULT NULL, + `mytext` longtext CHARACTER SET latin1 COLLATE latin1_general_cs DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin2 +drop table t1; +CREATE TABLE t1 (a int PRIMARY KEY, b INT UNIQUE); +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` int(11) DEFAULT NULL, + UNIQUE KEY `b` (`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 DROP PRIMARY KEY; +ERROR 42000: Can't DROP INDEX `PRIMARY`; check that it exists +DROP TABLE t1; +create table t1 (a int, b int, key(a)); +insert into t1 values (1,1), (2,2); +alter table t1 drop key no_such_key; +ERROR 42000: Can't DROP INDEX `no_such_key`; check that it exists +alter table t1 drop key a; +drop table t1; +CREATE TABLE T12207(a int) ENGINE=MYISAM; +ALTER TABLE T12207 DISCARD TABLESPACE; +ERROR HY000: Storage engine MyISAM of the table `test`.`T12207` doesn't have this option +DROP TABLE T12207; +create table t1 (a text) character set koi8r; +insert into t1 values (_koi8r'����'); +select hex(a) from t1; +hex(a) +D4C5D3D4 +alter table t1 convert to character set cp1251; +select hex(a) from t1; +hex(a) +F2E5F1F2 +drop table t1; +create table t1 ( a timestamp ); +alter table t1 add unique ( a(1) ); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +drop table t1; +drop table if exists t1; +create table t1 (a int, key(a)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +"this used not to disable the index" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +alter table t1 add b char(10), disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +alter table t1 add c decimal(10,2), enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +"this however did" +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +desc t1; +Field Type Null Key Default Extra +a bigint(20) YES MUL NULL +b char(10) YES NULL +c decimal(10,2) YES NULL +alter table t1 add d decimal(15,5); +"The key should still be disabled" +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A NULL NULL NULL YES BTREE disabled +drop table t1; +"Now will test with one unique index" +create table t1(a int, b char(10), unique(a)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 enable keys; +"If no copy on noop change, this won't touch the data file" +"Unique index, no change" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +"Change the type implying data copy" +"Unique index, no change" +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 modify a bigint; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +drop table t1; +"Now will test with one unique and one non-unique index" +create table t1(a int, b char(10), unique(a), key(b)); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +alter table t1 disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +"If no copy on noop change, this won't touch the data file" +"The non-unique index will be disabled" +alter table t1 modify a int, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +alter table t1 enable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE +"Change the type implying data copy" +"The non-unique index will be disabled" +alter table t1 modify a bigint, disable keys; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +"Change again the type, but leave the indexes as_is" +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +"Try the same. When data is no copied on similar tables, this is noop" +alter table t1 modify a int; +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 b 1 b A NULL NULL NULL YES BTREE disabled +drop table t1; +create database mysqltest; +create table t1 (c1 int); +alter table t1 rename mysqltest.t1; +drop table t1; +ERROR 42S02: Unknown table 'test.t1' +alter table mysqltest.t1 rename t1; +drop table t1; +create table t1 (c1 int); +use mysqltest; +drop database mysqltest; +alter table test.t1 rename t1; +ERROR 3D000: No database selected +alter table test.t1 rename test.t1; +use test; +drop table t1; +CREATE TABLE t1(a INT) ROW_FORMAT=FIXED; +CREATE INDEX i1 ON t1(a); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + KEY `i1` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED +DROP INDEX i1 ON t1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED +DROP TABLE t1; +DROP TABLE IF EXISTS bug24219; +DROP TABLE IF EXISTS bug24219_2; +CREATE TABLE bug24219 (a INT, INDEX(a)); +SHOW INDEX FROM bug24219; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +bug24219 1 a 1 a A NULL NULL NULL YES BTREE +ALTER TABLE bug24219 RENAME TO bug24219_2, DISABLE KEYS; +SHOW INDEX FROM bug24219_2; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +bug24219_2 1 a 1 a A NULL NULL NULL YES BTREE disabled +DROP TABLE bug24219_2; +drop table if exists table_24562; +create table table_24562( +section int, +subsection int, +title varchar(50)); +insert into table_24562 values +(1, 0, "Introduction"), +(1, 1, "Authors"), +(1, 2, "Acknowledgements"), +(2, 0, "Basics"), +(2, 1, "Syntax"), +(2, 2, "Client"), +(2, 3, "Server"), +(3, 0, "Intermediate"), +(3, 1, "Complex queries"), +(3, 2, "Stored Procedures"), +(3, 3, "Stored Functions"), +(4, 0, "Advanced"), +(4, 1, "Replication"), +(4, 2, "Load balancing"), +(4, 3, "High availability"), +(5, 0, "Conclusion"); +select * from table_24562; +section subsection title +1 0 Introduction +1 1 Authors +1 2 Acknowledgements +2 0 Basics +2 1 Syntax +2 2 Client +2 3 Server +3 0 Intermediate +3 1 Complex queries +3 2 Stored Procedures +3 3 Stored Functions +4 0 Advanced +4 1 Replication +4 2 Load balancing +4 3 High availability +5 0 Conclusion +alter table table_24562 add column reviewer varchar(20), +order by title; +select * from table_24562; +section subsection title reviewer +1 2 Acknowledgements NULL +4 0 Advanced NULL +1 1 Authors NULL +2 0 Basics NULL +2 2 Client NULL +3 1 Complex queries NULL +5 0 Conclusion NULL +4 3 High availability NULL +3 0 Intermediate NULL +1 0 Introduction NULL +4 2 Load balancing NULL +4 1 Replication NULL +2 3 Server NULL +3 3 Stored Functions NULL +3 2 Stored Procedures NULL +2 1 Syntax NULL +update table_24562 set reviewer="Me" where section=2; +update table_24562 set reviewer="You" where section=3; +alter table table_24562 +order by section ASC, subsection DESC; +select * from table_24562; +section subsection title reviewer +1 2 Acknowledgements NULL +1 1 Authors NULL +1 0 Introduction NULL +2 3 Server Me +2 2 Client Me +2 1 Syntax Me +2 0 Basics Me +3 3 Stored Functions You +3 2 Stored Procedures You +3 1 Complex queries You +3 0 Intermediate You +4 3 High availability NULL +4 2 Load balancing NULL +4 1 Replication NULL +4 0 Advanced NULL +5 0 Conclusion NULL +alter table table_24562 +order by table_24562.subsection ASC, table_24562.section DESC; +select * from table_24562; +section subsection title reviewer +5 0 Conclusion NULL +4 0 Advanced NULL +3 0 Intermediate You +2 0 Basics Me +1 0 Introduction NULL +4 1 Replication NULL +3 1 Complex queries You +2 1 Syntax Me +1 1 Authors NULL +4 2 Load balancing NULL +3 2 Stored Procedures You +2 2 Client Me +1 2 Acknowledgements NULL +4 3 High availability NULL +3 3 Stored Functions You +2 3 Server Me +alter table table_24562 order by 12; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '12' at line 1 +alter table table_24562 order by (section + 12); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(section + 12)' at line 1 +alter table table_24562 order by length(title); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(title)' at line 1 +alter table table_24562 order by (select 12 from dual); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(select 12 from dual)' at line 1 +alter table table_24562 order by no_such_col; +ERROR 42S22: Unknown column 'no_such_col' in 'order clause' +drop table table_24562; +create table t1 (mycol int(10) not null); +alter table t1 alter column mycol set default 0; +desc t1; +Field Type Null Key Default Extra +mycol int(10) NO 0 +drop table t1; +create table t1(id int(8) primary key auto_increment) engine=heap; +insert into t1 values (null); +insert into t1 values (null); +select * from t1; +id +1 +2 +alter table t1 auto_increment = 50; +alter table t1 engine = myisam; +insert into t1 values (null); +select * from t1; +id +1 +2 +50 +alter table t1 engine = heap; +insert into t1 values (null); +select * from t1; +id +1 +2 +50 +51 +drop table t1; +set @orig_sql_mode = @@sql_mode; +set sql_mode="no_zero_date"; +create table t1(f1 int); +alter table t1 add column f2 datetime not null, add column f21 date not null; +insert into t1 values(1,'2000-01-01','2000-01-01'); +alter table t1 add column f3 datetime not null; +ERROR 22007: Incorrect datetime value: '0000-00-00 00:00:00' for column 'f3' at row 1 +alter table t1 add column f3 date not null; +ERROR 22007: Incorrect date value: '0000-00-00' for column 'f3' at row 1 +alter table t1 add column f4 datetime not null default '2002-02-02', +add column f41 date not null; +ERROR 22007: Incorrect date value: '0000-00-00' for column 'f41' at row 1 +alter table t1 add column f4 datetime not null default '2002-02-02', +add column f41 date not null default '2002-02-02'; +select * from t1; +f1 f2 f21 f4 f41 +1 2000-01-01 00:00:00 2000-01-01 2002-02-02 00:00:00 2002-02-02 +drop table t1; +set sql_mode= @orig_sql_mode; +create table t1 (v varchar(32)); +insert into t1 values ('def'),('abc'),('hij'),('3r4f'); +select * from t1; +v +def +abc +hij +3r4f +alter table t1 change v v2 varchar(32); +select * from t1; +v2 +def +abc +hij +3r4f +alter table t1 change v2 v varchar(64); +select * from t1; +v +def +abc +hij +3r4f +update t1 set v = 'lmn' where v = 'hij'; +select * from t1; +v +def +abc +lmn +3r4f +alter table t1 add i int auto_increment not null primary key first; +select * from t1; +i v +1 def +2 abc +3 lmn +4 3r4f +update t1 set i=5 where i=3; +select * from t1; +i v +1 def +2 abc +5 lmn +4 3r4f +alter table t1 change i i bigint; +select * from t1; +i v +1 def +2 abc +5 lmn +4 3r4f +alter table t1 add unique key (i, v); +select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn'); +i v +4 3r4f +drop table t1; +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; +CREATE TABLE t1 (a varchar(500)); +ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) DEFAULT NULL, + `b` geometry NOT NULL, + SPATIAL KEY `b` (`b`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD KEY(b(50)); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) DEFAULT NULL, + `b` geometry NOT NULL, + SPATIAL KEY `b` (`b`), + KEY `b_2` (`b`(50)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t1 ADD c POINT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(500) DEFAULT NULL, + `b` geometry NOT NULL, + `c` point DEFAULT NULL, + SPATIAL KEY `b` (`b`), + KEY `b_2` (`b`(50)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CREATE TABLE t2 (a INT, KEY (a(20))); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +ALTER TABLE t1 ADD d INT; +ALTER TABLE t1 ADD KEY (d(20)); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30)); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +DROP TABLE t1; +CREATE TABLE t1 (s CHAR(8) BINARY); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +LENGTH(s) +4 +ALTER TABLE t1 MODIFY s CHAR(10) BINARY; +SELECT LENGTH(s) FROM t1; +LENGTH(s) +4 +DROP TABLE t1; +CREATE TABLE t1 (s BINARY(8)); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +LENGTH(s) +8 +SELECT HEX(s) FROM t1; +HEX(s) +7465737400000000 +ALTER TABLE t1 MODIFY s BINARY(10); +SELECT HEX(s) FROM t1; +HEX(s) +74657374000000000000 +SELECT LENGTH(s) FROM t1; +LENGTH(s) +10 +DROP TABLE t1; +CREATE TABLE t1 (v VARCHAR(3), b INT); +INSERT INTO t1 VALUES ('abc', 5); +SELECT * FROM t1; +v b +abc 5 +ALTER TABLE t1 MODIFY COLUMN v VARCHAR(4); +SELECT * FROM t1; +v b +abc 5 +DROP TABLE t1; +create table t1 (a tinytext character set latin1); +alter table t1 convert to character set utf8; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` text DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 +drop table t1; +create table t1 (a mediumtext character set latin1); +alter table t1 convert to character set utf8; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` longtext DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 +drop table t1; +End of 5.0 tests +drop table if exists t1, t2, t3; +create table t1 (i int); +create table t3 (j int); +insert into t1 values (); +insert into t3 values (); +lock table t1 write, t3 read; +alter table t1 modify i int default 1; +insert into t1 values (); +select * from t1; +i +NULL +1 +alter table t1 change i c char(10) default "Two"; +insert into t1 values (); +select * from t1; +c +NULL +1 +Two +alter table t1 modify c char(10) default "Three", rename to t2; +select * from t1; +ERROR HY000: Table 't1' was not locked with LOCK TABLES +select * from t2; +ERROR HY000: Table 't2' was not locked with LOCK TABLES +select * from t3; +j +NULL +unlock tables; +insert into t2 values (); +select * from t2; +c +NULL +1 +Two +Three +lock table t2 write, t3 read; +alter table t2 change c vc varchar(100) default "Four", rename to t1; +select * from t1; +ERROR HY000: Table 't1' was not locked with LOCK TABLES +select * from t2; +ERROR HY000: Table 't2' was not locked with LOCK TABLES +select * from t3; +j +NULL +unlock tables; +insert into t1 values (); +select * from t1; +vc +NULL +1 +Two +Three +Four +drop tables t1, t3; +DROP TABLE IF EXISTS `t+1`, `t+2`; +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +ERROR 42S01: Table 't+2' already exists +DROP TABLE `t+1`, `t+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +ERROR 42S01: Table 'tt+2' already exists +SHOW CREATE TABLE `tt+1`; +Table Create Table +tt+1 CREATE TEMPORARY TABLE `tt+1` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE `tt+2`; +Table Create Table +tt+2 CREATE TEMPORARY TABLE `tt+2` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE `tt+1`, `tt+2`; +CREATE TABLE `#sql1` (c1 INT); +CREATE TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +Tables_in_test +#sql1 +@0023sql2 +RENAME TABLE `#sql1` TO `@0023sql1`; +RENAME TABLE `@0023sql2` TO `#sql2`; +SHOW TABLES; +Tables_in_test +#sql2 +@0023sql1 +ALTER TABLE `@0023sql1` RENAME `#sql-1`; +ALTER TABLE `#sql2` RENAME `@0023sql-2`; +SHOW TABLES; +Tables_in_test +#sql-1 +@0023sql-2 +INSERT INTO `#sql-1` VALUES (1); +INSERT INTO `@0023sql-2` VALUES (2); +DROP TABLE `#sql-1`, `@0023sql-2`; +CREATE TEMPORARY TABLE `#sql1` (c1 INT); +CREATE TEMPORARY TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +Tables_in_test +ALTER TABLE `#sql1` RENAME `@0023sql1`; +ALTER TABLE `@0023sql2` RENAME `#sql2`; +SHOW TABLES; +Tables_in_test +INSERT INTO `#sql2` VALUES (1); +INSERT INTO `@0023sql1` VALUES (2); +SHOW CREATE TABLE `#sql2`; +Table Create Table +#sql2 CREATE TEMPORARY TABLE `#sql2` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE `@0023sql1`; +Table Create Table +@0023sql1 CREATE TEMPORARY TABLE `@0023sql1` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE `#sql2`, `@0023sql1`; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +CREATE TABLE t1 ( +int_field INTEGER UNSIGNED NOT NULL, +char_field CHAR(10), +INDEX(`int_field`) +); +DESCRIBE t1; +Field Type Null Key Default Extra +int_field int(10) unsigned NO MUL NULL +char_field char(10) YES NULL +SHOW INDEXES FROM t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 int_field 1 int_field A NULL NULL NULL BTREE +INSERT INTO t1 VALUES (1, "edno"), (1, "edno"), (2, "dve"), (3, "tri"), (5, "pet"); +"Non-copy data change - new frm, but old data and index files" +ALTER TABLE t1 +CHANGE int_field unsigned_int_field INTEGER UNSIGNED NOT NULL, +RENAME t2; +SELECT * FROM t1 ORDER BY int_field; +ERROR 42S02: Table 'test.t1' doesn't exist +SELECT * FROM t2 ORDER BY unsigned_int_field; +unsigned_int_field char_field +1 edno +1 edno +2 dve +3 tri +5 pet +DESCRIBE t2; +Field Type Null Key Default Extra +unsigned_int_field int(10) unsigned NO MUL NULL +char_field char(10) YES NULL +DESCRIBE t2; +Field Type Null Key Default Extra +unsigned_int_field int(10) unsigned NO MUL NULL +char_field char(10) YES NULL +ALTER TABLE t2 MODIFY unsigned_int_field BIGINT UNSIGNED NOT NULL; +DESCRIBE t2; +Field Type Null Key Default Extra +unsigned_int_field bigint(20) unsigned NO MUL NULL +char_field char(10) YES NULL +DROP TABLE t2; +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT); +INSERT INTO t1 VALUES (1, 2, NULL); +SELECT * FROM t1; +f1 f2 f3 +1 2 NULL +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f1; +SELECT * FROM t1; +f1 f3 f2 +1 NULL 2 +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f2; +SELECT * FROM t1; +f1 f2 f3 +1 2 NULL +DROP TABLE t1; +create table t1 (c char(10) default "Two"); +lock table t1 write; +insert into t1 values (); +alter table t1 modify c char(10) default "Three"; +unlock tables; +select * from t1; +c +Two +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (id int, c int) character set latin1; +INSERT INTO t1 VALUES (1,1); +ALTER TABLE t1 CHANGE c d int; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 CHANGE d c int; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 MODIFY c VARCHAR(10); +affected rows: 1 +info: Records: 1 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 CHANGE c d varchar(10); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 CHANGE d c varchar(10); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (id int, c int) character set utf8; +INSERT INTO t1 VALUES (1,1); +ALTER TABLE t1 CHANGE c d int; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 CHANGE d c int; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 MODIFY c VARCHAR(10); +affected rows: 1 +info: Records: 1 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 CHANGE c d varchar(10); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 CHANGE d c varchar(10); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +create table t1(f1 int not null, f2 int not null, key (f1), key (f2)); +select index_length into @unpaked_keys_size from +information_schema.tables where table_name='t1'; +alter table t1 pack_keys=1; +select index_length into @paked_keys_size from +information_schema.tables where table_name='t1'; +select (@unpaked_keys_size > @paked_keys_size); +(@unpaked_keys_size > @paked_keys_size) +1 +select max_data_length into @orig_max_data_length from +information_schema.tables where table_name='t1'; +alter table t1 max_rows=100; +select max_data_length into @changed_max_data_length from +information_schema.tables where table_name='t1'; +select (@orig_max_data_length > @changed_max_data_length); +(@orig_max_data_length > @changed_max_data_length) +1 +drop table t1; +CREATE TABLE t1(a INT AUTO_INCREMENT PRIMARY KEY, +b ENUM('a', 'b', 'c') NOT NULL); +INSERT INTO t1 (b) VALUES ('a'), ('c'), ('b'), ('b'), ('a'); +ALTER TABLE t1 MODIFY b ENUM('a', 'z', 'b', 'c') NOT NULL; +SELECT * FROM t1; +a b +1 a +2 c +3 b +4 b +5 a +DROP TABLE t1; +SET @save_sql_mode=@@sql_mode; +SET sql_mode=strict_all_tables; +CREATE TABLE t1 (a int NOT NULL default 42); +INSERT INTO t1 values (); +SELECT * FROM t1; +a +42 +ALTER TABLE t1 ALTER COLUMN a DROP DEFAULT; +INSERT INTO t1 values (); +ERROR HY000: Field 'a' doesn't have a default value +INSERT INTO t1 (a) VALUES (11); +SELECT * FROM t1 ORDER BY a; +a +11 +42 +DROP TABLE t1; +SET @@sql_mode=@save_sql_mode; +# +# Bug#45567: Fast ALTER TABLE broken for enum and set +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a ENUM('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +# No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# No copy: Add new enumeration to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a3'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx','a5'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Add new enumeration +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# No copy: Add new enumerations to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx','a5','a6'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +CREATE TABLE t1 (a SET('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +# No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a3'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx','a5'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Add new member +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Numerical incrase (pack lenght) +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6','a7','a8','a9','a10'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +CREATE TABLE t1 (f1 TIMESTAMP NULL DEFAULT NULL, +f2 INT(11) DEFAULT NULL) ENGINE=MYISAM DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES (NULL, NULL), ("2009-10-09 11:46:19", 2); +this should affect no rows as there is no real change +ALTER TABLE t1 CHANGE COLUMN f1 f1_no_real_change TIMESTAMP NULL DEFAULT NULL; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +# +# Bug #31145: ALTER TABLE DROP COLUMN, ADD COLUMN crashes (linux) +# or freezes (win) the server +# +CREATE TABLE t1 (a TEXT, id INT, b INT); +ALTER TABLE t1 DROP COLUMN a, ADD COLUMN c TEXT FIRST; +DROP TABLE t1; +# +# Test for bug #12652385 - "61493: REORDERING COLUMNS TO POSITION +# FIRST CAN CAUSE DATA TO BE CORRUPTED". +# +drop table if exists t1; +# Use MyISAM engine as the fact that InnoDB doesn't support +# in-place ALTER TABLE in cases when columns are being renamed +# hides some bugs. +create table t1 (i int, j int) engine=myisam; +insert into t1 value (1, 2); +# First, test for original problem described in the bug report. +select * from t1; +i j +1 2 +# Change of column order by the below ALTER TABLE statement should +# affect both column names and column contents. +alter table t1 modify column j int first; +select * from t1; +j i +2 1 +# Now test for similar problem with the same root. +# The below ALTER TABLE should change not only the name but +# also the value for the last column of the table. +alter table t1 drop column i, add column k int default 0; +select * from t1; +j k +2 0 +# Clean-up. +drop table t1; +End of 5.1 tests +CREATE TABLE t1(c CHAR(10), +i INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES('a',2),('b',4),('c',6); +ALTER TABLE t1 +DROP i, +ADD i INT UNSIGNED NOT NULL AUTO_INCREMENT, +AUTO_INCREMENT = 1; +DROP TABLE t1; +CREATE TABLE t1 (a CHAR(1), PRIMARY KEY (a(255))); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +CREATE TABLE t1 (a CHAR(1)); +ALTER TABLE t1 ADD PRIMARY KEY (a(20)); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +ALTER TABLE t1 ADD KEY (a(20)); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +CREATE UNIQUE INDEX i1 ON t1 (a(20)); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +CREATE INDEX i2 ON t1 (a(20)); +ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys +DROP TABLE t1; +CREATE TABLE t1 (id int); +INSERT INTO t1 VALUES (1), (2); +ALTER TABLE t1 ADD COLUMN (f1 INT), ADD COLUMN (f2 INT), ADD KEY f2k(f2); +DROP TABLE t1; +# +# Test for bug #53820 "ALTER a MEDIUMINT column table causes full +# table copy". +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT, b MEDIUMINT); +INSERT INTO t1 VALUES (1, 1), (2, 2); +# The below ALTER should not copy table and so no rows should +# be shown as affected. +ALTER TABLE t1 CHANGE a id INT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +# +# Bug#11754461 CANNOT ALTER TABLE WHEN KEY PREFIX TOO LONG +# +DROP DATABASE IF EXISTS db1; +CREATE DATABASE db1 CHARACTER SET utf8; +CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(100))); +ALTER TABLE db1.t1 ADD baz INT; +DROP DATABASE db1; +# Additional coverage for refactoring which is made as part +# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +# to allow temp table operations". +# +# At some point the below test case failed on assertion. +DROP TABLE IF EXISTS t1; +CREATE TEMPORARY TABLE t1 (i int) ENGINE=MyISAM; +ALTER TABLE t1 DISCARD TABLESPACE; +ERROR HY000: Storage engine MyISAM of the table `test`.`t1` doesn't have this option +DROP TABLE t1; +# +# Bug#11938039 RE-EXECUTION OF FRM-ONLY ALTER TABLE WITH RENAME +# CLAUSE FAILS OR ABORTS SERVER. +# +drop table if exists t1; +create table t1 (a int); +prepare stmt1 from 'alter table t1 alter column a set default 1, rename to t2'; +execute stmt1; +rename table t2 to t1; +# The below statement should succeed and not emit error or abort server. +execute stmt1; +deallocate prepare stmt1; +drop table t2; +# +# MDEV-8960 Can't refer the same column twice in one ALTER TABLE +# +CREATE TABLE t1 ( +`a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL, +ALTER COLUMN `consultant_id` DROP DEFAULT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `consultant_id` int(11) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 +DROP TABLE t1; +CREATE TABLE t1 ( +`a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL, +ALTER COLUMN `consultant_id` SET DEFAULT 2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `consultant_id` int(11) NOT NULL DEFAULT 2 +) ENGINE=MyISAM DEFAULT CHARSET=utf8 +DROP TABLE t1; +CREATE TABLE t1 ( +`a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL DEFAULT 2, +ALTER COLUMN `consultant_id` DROP DEFAULT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `consultant_id` int(11) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 +DROP TABLE t1; +CREATE TABLE t1 ( +`a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL DEFAULT 2, +ALTER COLUMN `consultant_id` DROP DEFAULT, +MODIFY COLUMN `consultant_id` BIGINT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `consultant_id` bigint(20) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8 +DROP TABLE t1; +CREATE TABLE t1 ( +id INT(11) NOT NULL, +x_param INT(11) DEFAULT NULL, +PRIMARY KEY (id) +) ENGINE=MYISAM; +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS id INT, +ADD COLUMN IF NOT EXISTS lol INT AFTER id; +Warnings: +Note 1060 Duplicate column name 'id' +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS lol INT AFTER id; +Warnings: +Note 1060 Duplicate column name 'lol' +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; +Warnings: +Note 1091 Can't DROP COLUMN `lol`; check that it exists +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +Warnings: +Note 1061 Duplicate key name 'x_param' +ALTER TABLE t1 MODIFY IF EXISTS lol INT; +Warnings: +Note 1054 Unknown column 'lol' in 't1' +DROP INDEX IF EXISTS x_param ON t1; +DROP INDEX IF EXISTS x_param ON t1; +Warnings: +Note 1091 Can't DROP INDEX `x_param`; check that it exists +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +Warnings: +Note 1061 Duplicate key name 'x_param1' +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `x_param` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `x_param1` (`x_param`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 ( +id INT(11) NOT NULL, +x_param INT(11) DEFAULT NULL, +PRIMARY KEY (id) +) ENGINE=INNODB; +CREATE TABLE t2 ( +id INT(11) NOT NULL) ENGINE=INNODB; +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS id INT, +ADD COLUMN IF NOT EXISTS lol INT AFTER id; +Warnings: +Note 1060 Duplicate column name 'id' +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS lol INT AFTER id; +Warnings: +Note 1060 Duplicate column name 'lol' +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; +Warnings: +Note 1091 Can't DROP COLUMN `lol`; check that it exists +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +Warnings: +Note 1061 Duplicate key name 'x_param' +ALTER TABLE t1 MODIFY IF EXISTS lol INT; +Warnings: +Note 1054 Unknown column 'lol' in 't1' +DROP INDEX IF EXISTS x_param ON t1; +DROP INDEX IF EXISTS x_param ON t1; +Warnings: +Note 1091 Can't DROP INDEX `x_param`; check that it exists +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +Warnings: +Note 1061 Duplicate key name 'x_param1' +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `x_param` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `x_param1` (`x_param`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +ALTER TABLE t2 ADD FOREIGN KEY IF NOT EXISTS fk(id) REFERENCES t1(id); +ALTER TABLE t2 ADD FOREIGN KEY IF NOT EXISTS fk(id) REFERENCES t1(id); +Warnings: +Note 1061 Duplicate key name 'fk' +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS fk; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS fk; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) NOT NULL, + KEY `fk` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +ALTER TABLE t2 ADD FOREIGN KEY (id) REFERENCES t1(id); +ALTER TABLE t2 ADD FOREIGN KEY IF NOT EXISTS t2_ibfk_1(id) REFERENCES t1(id); +Warnings: +Note 1061 Duplicate key name 't2_ibfk_1' +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS t2_ibfk_1; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS t2_ibfk_1; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `t2_ibfk_1`; check that it exists +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) NOT NULL, + KEY `id` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 ( +id INT(11) NOT NULL); +ALTER TABLE t2 ADD COLUMN a INT, ADD COLUMN IF NOT EXISTS a INT; +Warnings: +Note 1060 Duplicate column name 'a' +ALTER TABLE t2 ADD KEY k_id(id), ADD KEY IF NOT EXISTS k_id(id); +Warnings: +Note 1061 Duplicate key name 'k_id' +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) NOT NULL, + `a` int(11) DEFAULT NULL, + KEY `k_id` (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE t2 DROP KEY k_id, DROP KEY IF EXISTS k_id; +Warnings: +Note 1091 Can't DROP INDEX `k_id`; check that it exists +ALTER TABLE t2 DROP COLUMN a, DROP COLUMN IF EXISTS a; +Warnings: +Note 1091 Can't DROP COLUMN `a`; check that it exists +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `id` int(11) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +CREATE TABLE t1 ( +`transaction_id` int(11) NOT NULL DEFAULT '0', +KEY `transaction_id` (`transaction_id`)); +ALTER TABLE t1 DROP KEY IF EXISTS transaction_id, ADD PRIMARY KEY IF NOT EXISTS (transaction_id); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `transaction_id` int(11) NOT NULL DEFAULT 0, + PRIMARY KEY (`transaction_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# Bug#11748057 (formerly known as 34972): ALTER TABLE statement doesn't +# identify correct column name. +# +CREATE TABLE t1 (c1 int unsigned , c2 char(100) not null default ''); +ALTER TABLE t1 ADD c3 char(16) NOT NULL DEFAULT '' AFTER c2, +MODIFY c2 char(100) NOT NULL DEFAULT '' AFTER c1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(10) unsigned DEFAULT NULL, + `c2` char(100) NOT NULL DEFAULT '', + `c3` char(16) NOT NULL DEFAULT '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# WL#5534 Online ALTER, Phase 1 +# +# Single thread tests. +# See innodb_mysql_sync.test for multi thread tests. +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(a INT PRIMARY KEY, b INT) engine=InnoDB; +CREATE TABLE m1(a INT PRIMARY KEY, b INT) engine=MyISAM; +INSERT INTO t1 VALUES (1,1), (2,2); +INSERT INTO m1 VALUES (1,1), (2,2); +# +# 1: Test ALGORITHM keyword +# +# --enable_info allows us to see how many rows were updated +# by ALTER TABLE. in-place will show 0 rows, while copy > 0. +ALTER TABLE t1 ADD INDEX i1(b); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 ADD INDEX i2(b), ALGORITHM= DEFAULT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i2`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i3(b), ALGORITHM= COPY; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i3`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i4(b), ALGORITHM= INPLACE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i4`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i5(b), ALGORITHM= INVALID; +ERROR HY000: Unknown ALGORITHM 'INVALID' +ALTER TABLE m1 ENABLE KEYS; +affected rows: 0 +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= DEFAULT; +affected rows: 0 +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE; +affected rows: 0 +ALTER TABLE t1 DROP INDEX i1, DROP INDEX i2, DROP INDEX i3, DROP INDEX i4; +# +# 2: Test ALGORITHM + old_alter_table +# +SET SESSION old_alter_table= 1; +affected rows: 0 +ALTER TABLE t1 ADD INDEX i1(b); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 ADD INDEX i2(b), ALGORITHM= DEFAULT; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i2`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i3(b), ALGORITHM= COPY; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i3`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i4(b), ALGORITHM= INPLACE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i4`. This is deprecated and will be disallowed in a future release +SET SESSION old_alter_table= 0; +affected rows: 0 +ALTER TABLE t1 DROP INDEX i1, DROP INDEX i2, DROP INDEX i3, DROP INDEX i4; +# +# 3: Test unsupported in-place operation +# +ALTER TABLE t1 ADD COLUMN (c1 INT); +ALTER TABLE t1 ADD COLUMN (c2 INT), ALGORITHM= DEFAULT; +ALTER TABLE t1 ADD COLUMN (c3 INT), ALGORITHM= COPY; +ALTER TABLE t1 ADD COLUMN (c4 INT), ALGORITHM= INPLACE; +ALTER TABLE t1 DROP COLUMN c1, DROP COLUMN c2, DROP COLUMN c3, DROP COLUMN c4; +# +# 4: Test LOCK keyword +# +ALTER TABLE t1 ADD INDEX i1(b), LOCK= DEFAULT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 ADD INDEX i2(b), LOCK= NONE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i2`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i3(b), LOCK= SHARED; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i3`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i4(b), LOCK= EXCLUSIVE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i4`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i5(b), LOCK= INVALID; +ERROR HY000: Unknown LOCK type 'INVALID' +ALTER TABLE m1 ENABLE KEYS, LOCK= DEFAULT; +ALTER TABLE m1 ENABLE KEYS, LOCK= NONE; +ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE +ALTER TABLE m1 ENABLE KEYS, LOCK= SHARED; +ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE +ALTER TABLE m1 ENABLE KEYS, LOCK= EXCLUSIVE; +ALTER TABLE t1 DROP INDEX i1, DROP INDEX i2, DROP INDEX i3, DROP INDEX i4; +# +# 5: Test ALGORITHM + LOCK +# +ALTER TABLE t1 ADD INDEX i1(b), ALGORITHM= INPLACE, LOCK= NONE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 ADD INDEX i2(b), ALGORITHM= INPLACE, LOCK= SHARED; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i2`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i3(b), ALGORITHM= INPLACE, LOCK= EXCLUSIVE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i3`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i4(b), ALGORITHM= COPY, LOCK= NONE; +ERROR 0A000: LOCK=NONE is not supported. Reason: COPY algorithm requires a lock. Try LOCK=SHARED +ALTER TABLE t1 ADD INDEX i5(b), ALGORITHM= COPY, LOCK= SHARED; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i5`. This is deprecated and will be disallowed in a future release +ALTER TABLE t1 ADD INDEX i6(b), ALGORITHM= COPY, LOCK= EXCLUSIVE; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 1 +Warnings: +Note 1831 Duplicate index `i6`. This is deprecated and will be disallowed in a future release +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE, LOCK= NONE; +ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE, LOCK= SHARED; +ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE, LOCK= EXCLUSIVE; +affected rows: 0 +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY, LOCK= NONE; +ERROR 0A000: LOCK=NONE is not supported. Reason: COPY algorithm requires a lock. Try LOCK=SHARED +ALTER ONLINE TABLE m1 ADD COLUMN c int; +ERROR 0A000: LOCK=NONE is not supported for this operation. Try LOCK=SHARED +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY, LOCK= SHARED; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY, LOCK= EXCLUSIVE; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +DROP TABLE t1, m1; +# +# 6: Possible deadlock involving thr_lock.c +# +CREATE TABLE t1(a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); +START TRANSACTION; +INSERT INTO t1 VALUES (3,3); +connect con1, localhost, root; +# Sending: +ALTER TABLE t1 DISABLE KEYS; +connection default; +# Waiting until ALTER TABLE is blocked. +UPDATE t1 SET b = 4; +COMMIT; +connection con1; +# Reaping: ALTER TABLE t1 DISABLE KEYS +disconnect con1; +connection default; +DROP TABLE t1; +# +# 7: Which operations require copy and which can be done in-place? +# +# Test which ALTER TABLE operations are done in-place and +# which operations are done using temporary table copy. +# +# --enable_info allows us to see how many rows were updated +# by ALTER TABLE. in-place will show 0 rows, while copy > 0. +# +DROP TABLE IF EXISTS ti1, ti2, ti3, tm1, tm2, tm3; +# Single operation tests +CREATE TABLE ti1(a INT NOT NULL, b INT, c INT) engine=InnoDB; +CREATE TABLE tm1(a INT NOT NULL, b INT, c INT) engine=MyISAM; +CREATE TABLE ti2(a INT PRIMARY KEY AUTO_INCREMENT, b INT, c INT) engine=InnoDB; +CREATE TABLE tm2(a INT PRIMARY KEY AUTO_INCREMENT, b INT, c INT) engine=MyISAM; +INSERT INTO ti1 VALUES (1,1,1), (2,2,2); +INSERT INTO ti2 VALUES (1,1,1), (2,2,2); +INSERT INTO tm1 VALUES (1,1,1), (2,2,2); +INSERT INTO tm2 VALUES (1,1,1), (2,2,2); +ALTER TABLE ti1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD COLUMN d VARCHAR(200); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD COLUMN d VARCHAR(200); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD COLUMN d2 VARCHAR(200); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD COLUMN d2 VARCHAR(200); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD COLUMN e ENUM('a', 'b') FIRST; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD COLUMN e ENUM('a', 'b') FIRST; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD COLUMN f INT AFTER a; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD COLUMN f INT AFTER a; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD INDEX ii1(b); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD INDEX im1(b); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD UNIQUE INDEX ii2 (c); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD UNIQUE INDEX im2 (c); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD FULLTEXT INDEX ii3 (d); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD FULLTEXT INDEX im3 (d); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD FULLTEXT INDEX ii4 (d2); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD FULLTEXT INDEX im4 (d2); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD PRIMARY KEY(a), ALGORITHM=INPLACE; +ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: InnoDB presently supports one FULLTEXT index creation at a time. Try ALGORITHM=COPY +ALTER TABLE ti1 ADD PRIMARY KEY(a); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD PRIMARY KEY(a); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 DROP INDEX ii3; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 DROP INDEX im3; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 DROP COLUMN d2; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 DROP COLUMN d2; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ADD CONSTRAINT fi1 FOREIGN KEY (b) REFERENCES ti2(a); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ADD CONSTRAINT fm1 FOREIGN KEY (b) REFERENCES tm2(a); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ALTER COLUMN b SET DEFAULT 1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ALTER COLUMN b SET DEFAULT 1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 ALTER COLUMN b DROP DEFAULT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ALTER COLUMN b DROP DEFAULT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 CHANGE COLUMN f g INT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 CHANGE COLUMN f g INT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 CHANGE COLUMN g h VARCHAR(20); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 CHANGE COLUMN g h VARCHAR(20); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MODIFY COLUMN e ENUM('a', 'b', 'c'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MODIFY COLUMN e ENUM('a', 'b', 'c'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MODIFY COLUMN e INT; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MODIFY COLUMN e INT; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MODIFY COLUMN e INT AFTER h; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MODIFY COLUMN e INT AFTER h; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MODIFY COLUMN e INT FIRST; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MODIFY COLUMN e INT FIRST; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +SET @orig_sql_mode = @@sql_mode; +SET @@sql_mode = 'STRICT_TRANS_TABLES'; +ALTER TABLE ti1 MODIFY COLUMN c INT NOT NULL; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +SET @@sql_mode = @orig_sql_mode; +ALTER TABLE tm1 MODIFY COLUMN c INT NOT NULL; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MODIFY COLUMN c INT NULL; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MODIFY COLUMN c INT NULL; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MODIFY COLUMN h VARCHAR(30); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MODIFY COLUMN h VARCHAR(30); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MODIFY COLUMN h VARCHAR(30) AFTER d; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MODIFY COLUMN h VARCHAR(30) AFTER d; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 DROP COLUMN h; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 DROP COLUMN h; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 DROP INDEX ii2; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 DROP INDEX im2; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 DROP PRIMARY KEY; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 DROP PRIMARY KEY; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 DROP FOREIGN KEY fi1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 DROP FOREIGN KEY fm1; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 RENAME TO ti3; +affected rows: 0 +ALTER TABLE tm1 RENAME TO tm3; +affected rows: 0 +ALTER TABLE ti3 RENAME TO ti1; +affected rows: 0 +ALTER TABLE tm3 RENAME TO tm1; +affected rows: 0 +ALTER TABLE ti1 ORDER BY b; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 ORDER BY b; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 CONVERT TO CHARACTER SET utf16; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 CONVERT TO CHARACTER SET utf16; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 DEFAULT CHARACTER SET utf8; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 DEFAULT CHARACTER SET utf8; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 FORCE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 FORCE; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 AUTO_INCREMENT 3; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 AUTO_INCREMENT 3; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 AVG_ROW_LENGTH 10; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 AVG_ROW_LENGTH 10; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 CHECKSUM 1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 CHECKSUM 1; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 COMMENT 'test'; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 COMMENT 'test'; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MAX_ROWS 100; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MAX_ROWS 100; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 MIN_ROWS 1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 MIN_ROWS 1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti1 PACK_KEYS 1; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE tm1 PACK_KEYS 1; +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +DROP TABLE ti1, ti2, tm1, tm2; +# Tests of >1 operation (InnoDB) +CREATE TABLE ti1(a INT PRIMARY KEY AUTO_INCREMENT, b INT) engine=InnoDB; +INSERT INTO ti1(b) VALUES (1), (2); +ALTER TABLE ti1 RENAME TO ti3, ADD INDEX ii1(b); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE ti3 DROP INDEX ii1, AUTO_INCREMENT 5; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +INSERT INTO ti3(b) VALUES (5); +ALTER TABLE ti3 ADD INDEX ii1(b), AUTO_INCREMENT 7; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +INSERT INTO ti3(b) VALUES (7); +SELECT * FROM ti3; +a b +1 1 +2 2 +5 5 +7 7 +DROP TABLE ti3; +# +# 8: Scenario in which ALTER TABLE was returning an unwarranted +# ER_ILLEGAL_HA error at some point during work on this WL. +# +CREATE TABLE tm1(i INT DEFAULT 1) engine=MyISAM; +ALTER TABLE tm1 ADD INDEX ii1(i), ALTER COLUMN i DROP DEFAULT; +DROP TABLE tm1; +create table if not exists t1 (i int); +alter table t1 add key (i); +alter table t1 add key if not exists (i); +Warnings: +Note 1061 Duplicate key name 'i' +DROP TABLE t1; +create table t1 (a int); +alter table t1 change column if exists a b bigint; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` bigint(20) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +create table t1 (i int); +alter table t1 add unique index if not exists idx(i); +alter table t1 add unique index if not exists idx(i); +Warnings: +Note 1061 Duplicate key name 'idx' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL, + UNIQUE KEY `idx` (`i`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 ( +`event_id` bigint(20) unsigned NOT NULL DEFAULT '0', +`market_id` bigint(20) unsigned NOT NULL DEFAULT '0', +PRIMARY KEY (`event_id`,`market_id`) +); +ALTER TABLE t1 ADD PRIMARY KEY IF NOT EXISTS event_id (event_id,market_id); +Warnings: +Note 1061 Multiple primary key defined +DROP TABLE t1; +# +# MDEV-11126 Crash while altering persistent virtual column +# +CREATE TABLE `tab1` ( +`id` bigint(20) NOT NULL AUTO_INCREMENT, +`field2` set('option1','option2','option3','option4') NOT NULL, +`field3` set('option1','option2','option3','option4','option5') NOT NULL, +`field4` set('option1','option2','option3','option4') NOT NULL, +`field5` varchar(32) NOT NULL, +`field6` varchar(32) NOT NULL, +`field7` varchar(32) NOT NULL, +`field8` varchar(32) NOT NULL, +`field9` int(11) NOT NULL DEFAULT '1', +`field10` varchar(16) NOT NULL, +`field11` enum('option1','option2','option3') NOT NULL DEFAULT 'option1', +`v_col` varchar(128) AS (IF(field11='option1',CONCAT_WS(":","field1",field2,field3,field4,field5,field6,field7,field8,field9,field10), CONCAT_WS(":","field1",field11,field2,field3,field4,field5,field6,field7,field8,field9,field10))) PERSISTENT, +PRIMARY KEY (`id`) +) DEFAULT CHARSET=latin1; +ALTER TABLE `tab1` CHANGE COLUMN v_col `v_col` varchar(128); +SHOW CREATE TABLE `tab1`; +Table Create Table +tab1 CREATE TABLE `tab1` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `field2` set('option1','option2','option3','option4') NOT NULL, + `field3` set('option1','option2','option3','option4','option5') NOT NULL, + `field4` set('option1','option2','option3','option4') NOT NULL, + `field5` varchar(32) NOT NULL, + `field6` varchar(32) NOT NULL, + `field7` varchar(32) NOT NULL, + `field8` varchar(32) NOT NULL, + `field9` int(11) NOT NULL DEFAULT 1, + `field10` varchar(16) NOT NULL, + `field11` enum('option1','option2','option3') NOT NULL DEFAULT 'option1', + `v_col` varchar(128) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +ALTER TABLE `tab1` CHANGE COLUMN v_col `v_col` varchar(128) AS (IF(field11='option1',CONCAT_WS(":","field1",field2,field3,field4,field5,field6,field7,field8,field9,field10), CONCAT_WS(":","field1",field11,field2,field3,field4,field5,field6,field7,field8,field9,field10))) PERSISTENT; +SHOW CREATE TABLE `tab1`; +Table Create Table +tab1 CREATE TABLE `tab1` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `field2` set('option1','option2','option3','option4') NOT NULL, + `field3` set('option1','option2','option3','option4','option5') NOT NULL, + `field4` set('option1','option2','option3','option4') NOT NULL, + `field5` varchar(32) NOT NULL, + `field6` varchar(32) NOT NULL, + `field7` varchar(32) NOT NULL, + `field8` varchar(32) NOT NULL, + `field9` int(11) NOT NULL DEFAULT 1, + `field10` varchar(16) NOT NULL, + `field11` enum('option1','option2','option3') NOT NULL DEFAULT 'option1', + `v_col` varchar(128) GENERATED ALWAYS AS (if(`field11` = 'option1',concat_ws(':','field1',`field2`,`field3`,`field4`,`field5`,`field6`,`field7`,`field8`,`field9`,`field10`),concat_ws(':','field1',`field11`,`field2`,`field3`,`field4`,`field5`,`field6`,`field7`,`field8`,`field9`,`field10`))) STORED, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE `tab1`; +# +# MDEV-11548 Reproducible server crash after the 2nd ALTER TABLE ADD FOREIGN KEY IF NOT EXISTS +# +CREATE TABLE t1 (id INT UNSIGNED NOT NULL PRIMARY KEY); +CREATE TABLE t2 (id1 INT UNSIGNED NOT NULL); +ALTER TABLE t2 +ADD FOREIGN KEY IF NOT EXISTS (id1) +REFERENCES t1 (id); +ALTER TABLE t2 +ADD FOREIGN KEY IF NOT EXISTS (id1) +REFERENCES t1 (id); +Warnings: +Note 1061 Duplicate key name 'id1' +DROP TABLE t2; +DROP TABLE t1; +# +# MDEV-6390 CONVERT TO CHARACTER SET utf8 doesn't change DEFAULT CHARSET. +# +CREATE TABLE t1 (id int(11) NOT NULL, a int(11) NOT NULL, b int(11)) +ENGINE=InnoDB DEFAULT CHARSET=latin1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `a` int(11) NOT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +ALTER TABLE t1 CONVERT TO CHARACTER SET utf8; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `a` int(11) NOT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 +DROP TABLE t1; +# +# MDEV-15308 +# Assertion `ha_alter_info->alter_info->drop_list.elements > 0' failed +# in ha_innodb::prepare_inplace_alter_table +# +CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; +ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN b; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; +ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN b; +Warnings: +Note 1091 Can't DROP INDEX `fk`; check that it exists +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT, c INT, KEY(c)) ENGINE=InnoDB; +ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN c; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT, c INT, KEY c1(c)) ENGINE=InnoDB; +ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP INDEX c1; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `fk`; check that it exists +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; +ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN IF EXISTS c; +Warnings: +Note 1091 Can't DROP INDEX `fk`; check that it exists +Note 1091 Can't DROP COLUMN `c`; check that it exists +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# End of 10.0 tests +# +# +# MDEV-7374 : Losing connection to MySQL while running ALTER TABLE +# +CREATE TABLE t1(i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8); +INSERT INTO t1 SELECT a.* FROM t1 a, t1 b, t1 c, t1 d, t1 e; +ALTER TABLE t1 MODIFY i FLOAT; +DROP TABLE t1; +# +# MDEV-7816 ALTER with DROP INDEX and ADD INDEX .. COMMENT='comment2' ignores the new comment +# +CREATE TABLE t1(a INT); +CREATE INDEX i1 ON t1(a) COMMENT 'comment1'; +ALTER TABLE t1 DROP INDEX i1, ADD INDEX i1(a) COMMENT 'comment2'; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + KEY `i1` (`a`) COMMENT 'comment2' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# End of 10.1 tests +# +# +# MDEV-10421 duplicate CHECK CONSTRAINTs +# +CREATE TABLE t1 (a INT, b INT) engine=myisam; +ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100); +ALTER TABLE t1 ADD CONSTRAINT `min` CHECK (a+b > 100); +ERROR HY000: Duplicate CHECK constraint name 'min' +ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100); +Warnings: +Note 1826 Duplicate CHECK constraint name 'min' +ALTER TABLE t1 ADD CONSTRAINT `mini` CHECK (a+b > 100); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + CONSTRAINT `min` CHECK (`a` + `b` > 100), + CONSTRAINT `mini` CHECK (`a` + `b` > 100) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1(a INT, b INT, CONSTRAINT min check (a>5), +CONSTRAINT min check (b>5)); +ERROR HY000: Duplicate CHECK constraint name 'min' +create table t1 (a int, b int, check(a>b)); +alter table t1 drop column a; +ERROR 42S22: Unknown column 'a' in 'CHECK' +alter table t1 drop column b, add column b bigint first; +ERROR 42S22: Unknown column 'b' in 'CHECK' +alter table t1 drop column a, drop constraint constraint_1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int, b int, check(a>0)); +alter table t1 drop column a; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int, b int, check(a>0)); +alter table t1 drop column a, add column a bigint first; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int, b int, c int, unique(a)); +alter table t1 drop column a; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int, b int, c int, unique(a,b)); +alter table t1 drop column a; +ERROR 42000: Key column 'a' doesn't exist in table +alter table t1 drop column a, drop index a; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL, + `c` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (i int); +alter table t1 alter column if exists a set default 1; +Warnings: +Note 1054 Unknown column 'a' in 't1' +alter table t1 alter column if exists a drop default; +Warnings: +Note 1054 Unknown column 'a' in 't1' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# +# MDEV-13508 Check that rename of columns changes defaults, virtual +# columns and constraints +# +create table t1 (a int, b int, check(a>b)); +alter table t1 change column a b int, change column b a int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `b` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + CONSTRAINT `CONSTRAINT_1` CHECK (`b` > `a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a int primary key, b int, c int default (a+b) check (a+b>0), +d int as (a+b), +key (b), +constraint test check (a+b > 1)); +alter table t1 change b new_b int not null, add column b char(1), add constraint new check (length(b) > 0); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `new_b` int(11) NOT NULL, + `c` int(11) DEFAULT (`a` + `new_b`) CHECK (`a` + `new_b` > 0), + `d` int(11) GENERATED ALWAYS AS (`a` + `new_b`) VIRTUAL, + `b` char(1) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`new_b`), + CONSTRAINT `test` CHECK (`a` + `new_b` > 1), + CONSTRAINT `new` CHECK (octet_length(`b`) > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# ++# MDEV-11071: Assertion `thd->transaction.stmt.is_empty()' failed ++# in Locked_tables_list::unlock_locked_tables ++# ++CREATE TABLE t1 (d DATETIME DEFAULT CURRENT_TIMESTAMP, i INT) ENGINE=InnoDB; ++INSERT INTO t1 (i) VALUES (1),(1); ++LOCK TABLE t1 WRITE; ++ALTER TABLE t1 ADD UNIQUE(i); ++ERROR 23000: Duplicate entry '1' for key 'i' ++UNLOCK TABLES; ++DROP TABLE t1; ++# +# End of 10.2 tests +# diff --cc mysql-test/main/alter_table.test index aa9faf710f5,00000000000..c9302d588da mode 100644,000000..100644 --- a/mysql-test/main/alter_table.test +++ b/mysql-test/main/alter_table.test @@@ -1,1942 -1,0 +1,1958 @@@ +--source include/have_innodb.inc +# +# Test of alter table +# +--disable_warnings +drop table if exists t1,t2; +drop database if exists mysqltest; +--enable_warnings + +create table t1 ( +col1 int not null auto_increment primary key, +col2 varchar(30) not null, +col3 varchar (20) not null, +col4 varchar(4) not null, +col5 enum('PENDING', 'ACTIVE', 'DISABLED') not null, +col6 int not null, to_be_deleted int); +insert into t1 values (2,4,3,5,"PENDING",1,7); +alter table t1 +add column col4_5 varchar(20) not null after col4, +add column col7 varchar(30) not null after col5, +add column col8 datetime not null, drop column to_be_deleted, +change column col2 fourth varchar(30) not null after col3, +modify column col6 int not null first; +select * from t1; +drop table t1; + +create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); +insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); +alter table t1 add column new_col int, order by payoutid,bandid; +select * from t1; +alter table t1 order by bandid,payoutid; +select * from t1; +drop table t1; + +# Check that pack_keys and dynamic length rows are not forced. + +CREATE TABLE t1 ( +GROUP_ID int(10) unsigned DEFAULT '0' NOT NULL, +LANG_ID smallint(5) unsigned DEFAULT '0' NOT NULL, +NAME varchar(80) DEFAULT '' NOT NULL, +PRIMARY KEY (GROUP_ID,LANG_ID), +KEY NAME (NAME)); +#show table status like "t1"; +ALTER TABLE t1 CHANGE NAME NAME CHAR(80) not null; +--replace_column 8 # +SHOW FULL COLUMNS FROM t1; +DROP TABLE t1; + +# +# Test of ALTER TABLE ... ORDER BY +# + +create table t1 (n int); +insert into t1 values(9),(3),(12),(10); +alter table t1 order by n; +select * from t1; +drop table t1; + +CREATE TABLE t1 ( + id int(11) unsigned NOT NULL default '0', + category_id tinyint(4) unsigned NOT NULL default '0', + type_id tinyint(4) unsigned NOT NULL default '0', + body text NOT NULL, + user_id int(11) unsigned NOT NULL default '0', + status enum('new','old') NOT NULL default 'new', + PRIMARY KEY (id) +) ENGINE=MyISAM; + +ALTER TABLE t1 ORDER BY t1.id, t1.status, t1.type_id, t1.user_id, t1.body; +DROP TABLE t1; + +# +# The following combination found a hang-bug in MyISAM +# + +CREATE TABLE t1 (AnamneseId int(10) unsigned NOT NULL auto_increment,B BLOB,PRIMARY KEY (AnamneseId)) engine=myisam; +insert into t1 values (null,"hello"); +LOCK TABLES t1 WRITE; +ALTER TABLE t1 ADD Column new_col int not null; +UNLOCK TABLES; +OPTIMIZE TABLE t1; +DROP TABLE t1; + +# +# Drop and add an auto_increment column +# + +create table t1 (i int unsigned not null auto_increment primary key); +insert into t1 values (null),(null),(null),(null); +alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i); +select * from t1; +drop table t1; + +# +# Bug #2628: 'alter table t1 rename mysqltest.t1' silently drops mysqltest.t1 +# if it exists +# +create table t1 (name char(15)); +insert into t1 (name) values ("current"); +create database mysqltest; +create table mysqltest.t1 (name char(15)); +insert into mysqltest.t1 (name) values ("mysqltest"); +select * from t1; +select * from mysqltest.t1; +--error ER_TABLE_EXISTS_ERROR +alter table t1 rename mysqltest.t1; +select * from t1; +select * from mysqltest.t1; +drop table t1; +drop database mysqltest; + +# +# ALTER TABLE ... ENABLE/DISABLE KEYS + +create table t1 (n1 int not null, n2 int, n3 int, n4 float, + unique(n1), + key (n1, n2, n3, n4), + key (n2, n3, n4, n1), + key (n3, n4, n1, n2), + key (n4, n1, n2, n3) ); +alter table t1 disable keys; +show keys from t1; +#let $1=10000; +let $1=10; +--disable_query_log +begin; +while ($1) +{ + eval insert into t1 values($1,RAND()*1000,RAND()*1000,RAND()); + dec $1; +} +commit; +--enable_query_log +alter table t1 enable keys; +show keys from t1; +drop table t1; + +# +# Alter table and rename +# + +create table t1 (i int unsigned not null auto_increment primary key); +alter table t1 rename t2; +alter table t2 rename t1, add c char(10) comment "no comment"; +show columns from t1; +drop table t1; + +# implicit analyze + +create table t1 (a int, b int); +let $1=100; +--disable_query_log +begin; +while ($1) +{ + eval insert into t1 values(1,$1), (2,$1), (3, $1); + dec $1; +} +commit; +--enable_query_log +alter table t1 add unique (a,b), add key (b); +show keys from t1; +analyze table t1; +show keys from t1; +drop table t1; + +# +# Test of ALTER TABLE DELAYED +# + +CREATE TABLE t1 (i int(10), index(i) ) ENGINE=MyISAM; +ALTER TABLE t1 DISABLE KEYS; +INSERT DELAYED INTO t1 VALUES(1),(2),(3); +ALTER TABLE t1 ENABLE KEYS; +drop table t1; + +# +# Test ALTER TABLE ENABLE/DISABLE keys when things are locked +# + +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User) +) ENGINE=MyISAM; + +ALTER TABLE t1 DISABLE KEYS; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''),('games','monty'); +SHOW INDEX FROM t1; +ALTER TABLE t1 ENABLE KEYS; +UNLOCK TABLES; +CHECK TABLES t1; +DROP TABLE t1; + +# +# Test with two keys +# + +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User), + KEY (Host) +) ENGINE=MyISAM; + +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +LOCK TABLES t1 WRITE; +INSERT INTO t1 VALUES ('localhost','root'),('localhost',''); +SHOW INDEX FROM t1; +ALTER TABLE t1 ENABLE KEYS; +SHOW INDEX FROM t1; +UNLOCK TABLES; +CHECK TABLES t1; + +# Test RENAME with LOCK TABLES +LOCK TABLES t1 WRITE; +ALTER TABLE t1 RENAME t2; +UNLOCK TABLES; +select * from t2; +DROP TABLE t2; + +# +# Test disable keys with locking +# +CREATE TABLE t1 ( + Host varchar(16) binary NOT NULL default '', + User varchar(16) binary NOT NULL default '', + PRIMARY KEY (Host,User), + KEY (Host) +) ENGINE=MyISAM; + +LOCK TABLES t1 WRITE; +ALTER TABLE t1 DISABLE KEYS; +SHOW INDEX FROM t1; +DROP TABLE t1; + +# +# BUG#4717 - check for valid table names +# +create table t1 (a int); +--error ER_WRONG_TABLE_NAME +alter table t1 rename to ``; +--error ER_WRONG_TABLE_NAME +rename table t1 to ``; +drop table t1; + +# +# BUG#6236 - ALTER TABLE MODIFY should set implicit NOT NULL on PK columns +# +drop table if exists t1, t2; +create table t1 ( a varchar(10) not null primary key ) engine=myisam; +create table t2 ( a varchar(10) not null primary key ) engine=merge union=(t1); +flush tables; +alter table t1 modify a varchar(10); +show create table t2; +flush tables; +alter table t1 modify a varchar(10) not null; +show create table t2; +drop table if exists t1, t2; + +# The following is also part of bug #6236 (CREATE TABLE didn't properly count +# not null columns for primary keys) + +create table t1 (a int, b int, c int, d int, e int, f int, g int, h int,i int, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert ignore into t1 (a) values(1); +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X 19 X +show table status like 't1'; +alter table t1 modify a int; +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X 19 X +show table status like 't1'; +drop table t1; +create table t1 (a int not null, b int not null, c int not null, d int not null, e int not null, f int not null, g int not null, h int not null,i int not null, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM; +insert ignore into t1 (a) values(1); +--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X 19 X +show table status like 't1'; +drop table t1; + +# +# Test that data get converted when character set is changed +# Test that data doesn't get converted when src or dst is BINARY/BLOB +# +set names koi8r; +create table t1 (a char(10) character set koi8r); +insert into t1 values ('����'); +select a,hex(a) from t1; +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a binary(4); +select a,hex(a) from t1; +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +alter table t1 change a a varchar(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +alter table t1 change a a text character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +delete from t1; + +# +# Test ALTER TABLE .. CHARACTER SET .. +# +show create table t1; +alter table t1 DEFAULT CHARACTER SET latin1; +show create table t1; +alter table t1 CONVERT TO CHARACTER SET latin1; +show create table t1; +alter table t1 DEFAULT CHARACTER SET cp1251; +show create table t1; + +drop table t1; + +# +# Bug#2821 +# Test that table CHARACTER SET does not affect blobs +# +create table t1 (myblob longblob,mytext longtext) +default charset latin1 collate latin1_general_cs; +show create table t1; +alter table t1 character set latin2; +show create table t1; +drop table t1; + +# +# Bug 2361 (Don't drop UNIQUE with DROP PRIMARY KEY) +# + +CREATE TABLE t1 (a int PRIMARY KEY, b INT UNIQUE); +ALTER TABLE t1 DROP PRIMARY KEY; +SHOW CREATE TABLE t1; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t1 DROP PRIMARY KEY; +DROP TABLE t1; + +# BUG#3899 +create table t1 (a int, b int, key(a)); +insert into t1 values (1,1), (2,2); +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 drop key no_such_key; +alter table t1 drop key a; +drop table t1; + +# +# BUG 12207 alter table ... discard table space on MyISAM table causes ERROR 2013 (HY000) +# +# Some platforms (Mac OS X, Windows) will send the error message using small letters. +CREATE TABLE T12207(a int) ENGINE=MYISAM; +--replace_result t12207 T12207 +--error ER_ILLEGAL_HA +ALTER TABLE T12207 DISCARD TABLESPACE; +DROP TABLE T12207; + +# +# Bug #6479 ALTER TABLE ... changing charset fails for TEXT columns +# +# The column's character set was changed but the actual data was not +# modified. In other words, the values were reinterpreted +# as UTF8 instead of being converted. +create table t1 (a text) character set koi8r; +insert into t1 values (_koi8r'����'); +select hex(a) from t1; +alter table t1 convert to character set cp1251; +select hex(a) from t1; +drop table t1; + +# +# Test for bug #7884 "Able to add invalid unique index on TIMESTAMP prefix" +# MySQL should not think that packed field with non-zero decimals is +# geometry field and allow to create prefix index which is +# shorter than packed field length. +# +create table t1 ( a timestamp ); +--error ER_WRONG_SUB_KEY +alter table t1 add unique ( a(1) ); +drop table t1; + +# +# Bug #24395: ALTER TABLE DISABLE KEYS doesn't work when modifying the table +# +# This problem happens if the data change is compatible. +# Changing to the same type is compatible for example. +# +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int, key(a)); +show indexes from t1; +--echo "this used not to disable the index" +alter table t1 modify a int, disable keys; +show indexes from t1; + +alter table t1 enable keys; +show indexes from t1; + +alter table t1 modify a bigint, disable keys; +show indexes from t1; + +alter table t1 enable keys; +show indexes from t1; + +alter table t1 add b char(10), disable keys; +show indexes from t1; + +alter table t1 add c decimal(10,2), enable keys; +show indexes from t1; + +--echo "this however did" +alter table t1 disable keys; +show indexes from t1; + +desc t1; + +alter table t1 add d decimal(15,5); +--echo "The key should still be disabled" +show indexes from t1; + +drop table t1; + +--echo "Now will test with one unique index" +create table t1(a int, b char(10), unique(a)); +show indexes from t1; +alter table t1 disable keys; +show indexes from t1; +alter table t1 enable keys; + +--echo "If no copy on noop change, this won't touch the data file" +--echo "Unique index, no change" +alter table t1 modify a int, disable keys; +show indexes from t1; + +--echo "Change the type implying data copy" +--echo "Unique index, no change" +alter table t1 modify a bigint, disable keys; +show indexes from t1; + +alter table t1 modify a bigint; +show indexes from t1; + +alter table t1 modify a int; +show indexes from t1; + +drop table t1; + +--echo "Now will test with one unique and one non-unique index" +create table t1(a int, b char(10), unique(a), key(b)); +show indexes from t1; +alter table t1 disable keys; +show indexes from t1; +alter table t1 enable keys; + + +--echo "If no copy on noop change, this won't touch the data file" +--echo "The non-unique index will be disabled" +alter table t1 modify a int, disable keys; +show indexes from t1; +alter table t1 enable keys; +show indexes from t1; + +--echo "Change the type implying data copy" +--echo "The non-unique index will be disabled" +alter table t1 modify a bigint, disable keys; +show indexes from t1; + +--echo "Change again the type, but leave the indexes as_is" +alter table t1 modify a int; +show indexes from t1; +--echo "Try the same. When data is no copied on similar tables, this is noop" +alter table t1 modify a int; +show indexes from t1; + +drop table t1; + + +# +# Bug#11493 - Alter table rename to default database does not work without +# db name qualifying +# +create database mysqltest; +create table t1 (c1 int); +# Move table to other database. +alter table t1 rename mysqltest.t1; +# Assure that it has moved. +--error ER_BAD_TABLE_ERROR +drop table t1; +# Move table back. +alter table mysqltest.t1 rename t1; +# Assure that it is back. +drop table t1; +# Now test for correct message if no database is selected. +# Create t1 in 'test'. +create table t1 (c1 int); +# Change to other db. +use mysqltest; +# Drop the current db. This de-selects any db. +drop database mysqltest; +# Now test for correct message. +--error ER_NO_DB_ERROR +alter table test.t1 rename t1; +# Check that explicit qualifying works even with no selected db. +alter table test.t1 rename test.t1; +# Go back to standard 'test' db. +use test; +drop table t1; + +# +# BUG#23404 - ROW_FORMAT=FIXED option is lost is an index is added to the +# table +# +CREATE TABLE t1(a INT) ROW_FORMAT=FIXED; +CREATE INDEX i1 ON t1(a); +SHOW CREATE TABLE t1; +DROP INDEX i1 ON t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# +# Bug#24219 - ALTER TABLE ... RENAME TO ... , DISABLE KEYS leads to crash +# +--disable_warnings +DROP TABLE IF EXISTS bug24219; +DROP TABLE IF EXISTS bug24219_2; +--enable_warnings + +CREATE TABLE bug24219 (a INT, INDEX(a)); + +SHOW INDEX FROM bug24219; + +ALTER TABLE bug24219 RENAME TO bug24219_2, DISABLE KEYS; + +SHOW INDEX FROM bug24219_2; + +DROP TABLE bug24219_2; + +# +# Bug#24562 (ALTER TABLE ... ORDER BY ... with complex expression asserts) +# + +--disable_warnings +drop table if exists table_24562; +--enable_warnings + +create table table_24562( + section int, + subsection int, + title varchar(50)); + +insert into table_24562 values +(1, 0, "Introduction"), +(1, 1, "Authors"), +(1, 2, "Acknowledgements"), +(2, 0, "Basics"), +(2, 1, "Syntax"), +(2, 2, "Client"), +(2, 3, "Server"), +(3, 0, "Intermediate"), +(3, 1, "Complex queries"), +(3, 2, "Stored Procedures"), +(3, 3, "Stored Functions"), +(4, 0, "Advanced"), +(4, 1, "Replication"), +(4, 2, "Load balancing"), +(4, 3, "High availability"), +(5, 0, "Conclusion"); + +select * from table_24562; + +alter table table_24562 add column reviewer varchar(20), +order by title; + +select * from table_24562; + +update table_24562 set reviewer="Me" where section=2; +update table_24562 set reviewer="You" where section=3; + +alter table table_24562 +order by section ASC, subsection DESC; + +select * from table_24562; + +alter table table_24562 +order by table_24562.subsection ASC, table_24562.section DESC; + +select * from table_24562; + +--error ER_PARSE_ERROR +alter table table_24562 order by 12; +--error ER_PARSE_ERROR +alter table table_24562 order by (section + 12); +--error ER_PARSE_ERROR +alter table table_24562 order by length(title); +--error ER_PARSE_ERROR +alter table table_24562 order by (select 12 from dual); + +--error ER_BAD_FIELD_ERROR +alter table table_24562 order by no_such_col; + +drop table table_24562; + +# End of 4.1 tests + +# +# Bug #14693 (ALTER SET DEFAULT doesn't work) +# + +create table t1 (mycol int(10) not null); +alter table t1 alter column mycol set default 0; +desc t1; +drop table t1; + +# +# Bug#25262 Auto Increment lost when changing Engine type +# + +create table t1(id int(8) primary key auto_increment) engine=heap; + +insert into t1 values (null); +insert into t1 values (null); + +select * from t1; + +# Set auto increment to 50 +alter table t1 auto_increment = 50; + +# Alter to myisam +alter table t1 engine = myisam; + +# This insert should get id 50 +insert into t1 values (null); +select * from t1; + +# Alter to heap again +alter table t1 engine = heap; +insert into t1 values (null); +select * from t1; + +drop table t1; + +# +# Bug#27507: Wrong DATETIME value was allowed by ALTER TABLE in the +# NO_ZERO_DATE mode. +# +set @orig_sql_mode = @@sql_mode; +set sql_mode="no_zero_date"; +create table t1(f1 int); +alter table t1 add column f2 datetime not null, add column f21 date not null; +insert into t1 values(1,'2000-01-01','2000-01-01'); +--error 1292 +alter table t1 add column f3 datetime not null; +--error 1292 +alter table t1 add column f3 date not null; +--error 1292 +alter table t1 add column f4 datetime not null default '2002-02-02', + add column f41 date not null; +alter table t1 add column f4 datetime not null default '2002-02-02', + add column f41 date not null default '2002-02-02'; +select * from t1; +drop table t1; +set sql_mode= @orig_sql_mode; + +# +# Some additional tests for new, faster alter table. Note that most of the +# whole alter table code is being tested all around the test suite already. +# + +create table t1 (v varchar(32)); +insert into t1 values ('def'),('abc'),('hij'),('3r4f'); +select * from t1; +# Fast alter, no copy performed +alter table t1 change v v2 varchar(32); +select * from t1; +# Fast alter, no copy performed +alter table t1 change v2 v varchar(64); +select * from t1; +update t1 set v = 'lmn' where v = 'hij'; +select * from t1; +# Regular alter table +alter table t1 add i int auto_increment not null primary key first; +select * from t1; +update t1 set i=5 where i=3; +select * from t1; +alter table t1 change i i bigint; +select * from t1; +alter table t1 add unique key (i, v); +select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn'); +drop table t1; + +# +# Bug#6073 "ALTER table minor glich": ALTER TABLE complains that an index +# without # prefix is not allowed for TEXT columns, while index +# is defined with prefix. +# +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; + +# +# Bug #26794: Adding an index with a prefix on a SPATIAL type breaks ALTER +# TABLE +# +CREATE TABLE t1 (a varchar(500)); + +ALTER TABLE t1 ADD b GEOMETRY NOT NULL, ADD SPATIAL INDEX(b); +SHOW CREATE TABLE t1; +ALTER TABLE t1 ADD KEY(b(50)); +SHOW CREATE TABLE t1; + +ALTER TABLE t1 ADD c POINT; +SHOW CREATE TABLE t1; + +--error ER_WRONG_SUB_KEY +CREATE TABLE t2 (a INT, KEY (a(20))); + +ALTER TABLE t1 ADD d INT; +--error ER_WRONG_SUB_KEY +ALTER TABLE t1 ADD KEY (d(20)); + +# the 5.1 part of the test +--error ER_WRONG_SUB_KEY +ALTER TABLE t1 ADD e GEOMETRY NOT NULL, ADD SPATIAL KEY (e(30)); + +DROP TABLE t1; + +# +# Bug#18038 MySQL server corrupts binary columns data +# + +CREATE TABLE t1 (s CHAR(8) BINARY); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +ALTER TABLE t1 MODIFY s CHAR(10) BINARY; +SELECT LENGTH(s) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (s BINARY(8)); +INSERT INTO t1 VALUES ('test'); +SELECT LENGTH(s) FROM t1; +SELECT HEX(s) FROM t1; +ALTER TABLE t1 MODIFY s BINARY(10); +SELECT HEX(s) FROM t1; +SELECT LENGTH(s) FROM t1; +DROP TABLE t1; + +# +# Bug#19386: Multiple alter causes crashed table +# The trailing column would get corrupted data, or server could not even read +# it. +# + +CREATE TABLE t1 (v VARCHAR(3), b INT); +INSERT INTO t1 VALUES ('abc', 5); +SELECT * FROM t1; +ALTER TABLE t1 MODIFY COLUMN v VARCHAR(4); +SELECT * FROM t1; +DROP TABLE t1; + + +# +# Bug#31291 ALTER TABLE CONVERT TO CHARACTER SET does not change some data types +# +create table t1 (a tinytext character set latin1); +alter table t1 convert to character set utf8; +show create table t1; +drop table t1; +create table t1 (a mediumtext character set latin1); +alter table t1 convert to character set utf8; +show create table t1; +drop table t1; + +--echo End of 5.0 tests + +# +# Extended test coverage for ALTER TABLE behaviour under LOCK TABLES +# It should be consistent across all platforms and for all engines +# (Before 5.1 this was not true as behavior was different between +# Unix/Windows and transactional/non-transactional tables). +# See also innodb_mysql.test +# +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +create table t1 (i int); +create table t3 (j int); +insert into t1 values (); +insert into t3 values (); +# Table which is altered under LOCK TABLES it should stay in list of locked +# tables and be available after alter takes place unless ALTER contains RENAME +# clause. We should see the new definition of table, of course. +lock table t1 write, t3 read; +# Example of so-called 'fast' ALTER TABLE +alter table t1 modify i int default 1; +insert into t1 values (); +select * from t1; +# And now full-blown ALTER TABLE +alter table t1 change i c char(10) default "Two"; +insert into t1 values (); +select * from t1; +# If table is renamed then it should be removed from the list +# of locked tables. 'Fast' ALTER TABLE with RENAME clause: +alter table t1 modify c char(10) default "Three", rename to t2; +--error ER_TABLE_NOT_LOCKED +select * from t1; +--error ER_TABLE_NOT_LOCKED +select * from t2; +select * from t3; +unlock tables; +insert into t2 values (); +select * from t2; +lock table t2 write, t3 read; +# Full ALTER TABLE with RENAME +alter table t2 change c vc varchar(100) default "Four", rename to t1; +--error ER_TABLE_NOT_LOCKED +select * from t1; +--error ER_TABLE_NOT_LOCKED +select * from t2; +select * from t3; +unlock tables; +insert into t1 values (); +select * from t1; +drop tables t1, t3; + + +# +# Bug#18775 - Temporary table from alter table visible to other threads +# +# Check if special characters work and duplicates are detected. +--disable_warnings +DROP TABLE IF EXISTS `t+1`, `t+2`; +--enable_warnings +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +CREATE TABLE `t+1` (c1 INT); +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE `t+1` RENAME `t+2`; +DROP TABLE `t+1`, `t+2`; +# +# Same for temporary tables though these names do not become file names. +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE `tt+1` RENAME `tt+2`; +SHOW CREATE TABLE `tt+1`; +SHOW CREATE TABLE `tt+2`; +DROP TABLE `tt+1`, `tt+2`; +# +# Check if special characters as in tmp_file_prefix work. +CREATE TABLE `#sql1` (c1 INT); +CREATE TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +RENAME TABLE `#sql1` TO `@0023sql1`; +RENAME TABLE `@0023sql2` TO `#sql2`; +SHOW TABLES; +ALTER TABLE `@0023sql1` RENAME `#sql-1`; +ALTER TABLE `#sql2` RENAME `@0023sql-2`; +SHOW TABLES; +INSERT INTO `#sql-1` VALUES (1); +INSERT INTO `@0023sql-2` VALUES (2); +DROP TABLE `#sql-1`, `@0023sql-2`; +# +# Same for temporary tables though these names do not become file names. +CREATE TEMPORARY TABLE `#sql1` (c1 INT); +CREATE TEMPORARY TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +ALTER TABLE `#sql1` RENAME `@0023sql1`; +ALTER TABLE `@0023sql2` RENAME `#sql2`; +SHOW TABLES; +INSERT INTO `#sql2` VALUES (1); +INSERT INTO `@0023sql1` VALUES (2); +SHOW CREATE TABLE `#sql2`; +SHOW CREATE TABLE `@0023sql1`; +DROP TABLE `#sql2`, `@0023sql1`; + +# +# Bug #22369: Alter table rename combined with other alterations causes lost tables +# +# This problem happens if the data change is compatible. +# Changing to the same type is compatible for example. +# +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings +CREATE TABLE t1 ( + int_field INTEGER UNSIGNED NOT NULL, + char_field CHAR(10), + INDEX(`int_field`) +); + +DESCRIBE t1; + +SHOW INDEXES FROM t1; + +INSERT INTO t1 VALUES (1, "edno"), (1, "edno"), (2, "dve"), (3, "tri"), (5, "pet"); +--echo "Non-copy data change - new frm, but old data and index files" +ALTER TABLE t1 + CHANGE int_field unsigned_int_field INTEGER UNSIGNED NOT NULL, + RENAME t2; + +--error ER_NO_SUCH_TABLE +SELECT * FROM t1 ORDER BY int_field; +SELECT * FROM t2 ORDER BY unsigned_int_field; +DESCRIBE t2; +DESCRIBE t2; +ALTER TABLE t2 MODIFY unsigned_int_field BIGINT UNSIGNED NOT NULL; +DESCRIBE t2; + +DROP TABLE t2; + +# +# Bug#28427: Columns were renamed instead of moving by ALTER TABLE. +# +CREATE TABLE t1 (f1 INT, f2 INT, f3 INT); +INSERT INTO t1 VALUES (1, 2, NULL); +SELECT * FROM t1; +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f1; +SELECT * FROM t1; +ALTER TABLE t1 MODIFY COLUMN f3 INT AFTER f2; +SELECT * FROM t1; +DROP TABLE t1; + +# +# BUG#29957 - alter_table.test fails +# +create table t1 (c char(10) default "Two"); +lock table t1 write; +insert into t1 values (); +alter table t1 modify c char(10) default "Three"; +unlock tables; +select * from t1; +check table t1; +drop table t1; + +# +# Bug#33873: Fast ALTER TABLE doesn't work with multibyte character sets +# + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (id int, c int) character set latin1; +INSERT INTO t1 VALUES (1,1); +--enable_info +ALTER TABLE t1 CHANGE c d int; +ALTER TABLE t1 CHANGE d c int; +ALTER TABLE t1 MODIFY c VARCHAR(10); +ALTER TABLE t1 CHANGE c d varchar(10); +ALTER TABLE t1 CHANGE d c varchar(10); +--disable_info +DROP TABLE t1; + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (id int, c int) character set utf8; +INSERT INTO t1 VALUES (1,1); +--enable_info +ALTER TABLE t1 CHANGE c d int; +ALTER TABLE t1 CHANGE d c int; +ALTER TABLE t1 MODIFY c VARCHAR(10); +ALTER TABLE t1 CHANGE c d varchar(10); +ALTER TABLE t1 CHANGE d c varchar(10); +--disable_info +DROP TABLE t1; + +# +# Bug#39372 "Smart" ALTER TABLE not so smart after all. +# +create table t1(f1 int not null, f2 int not null, key (f1), key (f2)); +let $count= 50; +--disable_query_log +begin; +while ($count) +{ + EVAL insert into t1 values (1,1),(1,1),(1,1),(1,1),(1,1); + EVAL insert into t1 values (2,2),(2,2),(2,2),(2,2),(2,2); + dec $count ; +} +commit; +--enable_query_log + +select index_length into @unpaked_keys_size from +information_schema.tables where table_name='t1'; +alter table t1 pack_keys=1; +select index_length into @paked_keys_size from +information_schema.tables where table_name='t1'; +select (@unpaked_keys_size > @paked_keys_size); + +select max_data_length into @orig_max_data_length from +information_schema.tables where table_name='t1'; +alter table t1 max_rows=100; +select max_data_length into @changed_max_data_length from +information_schema.tables where table_name='t1'; +select (@orig_max_data_length > @changed_max_data_length); + +drop table t1; + +# +# Bug #23113: Different behavior on altering ENUM fields between 5.0 and 5.1 +# +CREATE TABLE t1(a INT AUTO_INCREMENT PRIMARY KEY, + b ENUM('a', 'b', 'c') NOT NULL); +INSERT INTO t1 (b) VALUES ('a'), ('c'), ('b'), ('b'), ('a'); +ALTER TABLE t1 MODIFY b ENUM('a', 'z', 'b', 'c') NOT NULL; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Test for ALTER column DROP DEFAULT +# + +SET @save_sql_mode=@@sql_mode; +SET sql_mode=strict_all_tables; + +CREATE TABLE t1 (a int NOT NULL default 42); +INSERT INTO t1 values (); +SELECT * FROM t1; +ALTER TABLE t1 ALTER COLUMN a DROP DEFAULT; +--error 1364 +INSERT INTO t1 values (); +INSERT INTO t1 (a) VALUES (11); +SELECT * FROM t1 ORDER BY a; +DROP TABLE t1; +SET @@sql_mode=@save_sql_mode; +--echo # +--echo # Bug#45567: Fast ALTER TABLE broken for enum and set +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a ENUM('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +--enable_info +--echo # No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2'); +--echo # No copy: Add new enumeration to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a3'); +--echo # Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx','a5'); +--echo # Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx'); +--echo # Copy: Add new enumeration +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx'); +--echo # No copy: Add new enumerations to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx','a5','a6'); +--disable_info +DROP TABLE t1; + +CREATE TABLE t1 (a SET('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +--enable_info +--echo # No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2'); +--echo # No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a3'); +--echo # Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx','a5'); +--echo # Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx'); +--echo # Copy: Add new member +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx'); +--echo # No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6'); +--echo # Copy: Numerical incrase (pack lenght) +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6','a7','a8','a9','a10'); +--disable_info +DROP TABLE t1; + +# +# Bug#43508: Renaming timestamp or date column triggers table copy +# + +CREATE TABLE t1 (f1 TIMESTAMP NULL DEFAULT NULL, + f2 INT(11) DEFAULT NULL) ENGINE=MYISAM DEFAULT CHARSET=utf8; + +INSERT INTO t1 VALUES (NULL, NULL), ("2009-10-09 11:46:19", 2); + +--echo this should affect no rows as there is no real change +--enable_info +ALTER TABLE t1 CHANGE COLUMN f1 f1_no_real_change TIMESTAMP NULL DEFAULT NULL; +--disable_info +DROP TABLE t1; + + +--echo # +--echo # Bug #31145: ALTER TABLE DROP COLUMN, ADD COLUMN crashes (linux) +--echo # or freezes (win) the server +--echo # + +CREATE TABLE t1 (a TEXT, id INT, b INT); +ALTER TABLE t1 DROP COLUMN a, ADD COLUMN c TEXT FIRST; + +DROP TABLE t1; + + +--echo # +--echo # Test for bug #12652385 - "61493: REORDERING COLUMNS TO POSITION +--echo # FIRST CAN CAUSE DATA TO BE CORRUPTED". +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +--echo # Use MyISAM engine as the fact that InnoDB doesn't support +--echo # in-place ALTER TABLE in cases when columns are being renamed +--echo # hides some bugs. +create table t1 (i int, j int) engine=myisam; +insert into t1 value (1, 2); +--echo # First, test for original problem described in the bug report. +select * from t1; +--echo # Change of column order by the below ALTER TABLE statement should +--echo # affect both column names and column contents. +alter table t1 modify column j int first; +select * from t1; +--echo # Now test for similar problem with the same root. +--echo # The below ALTER TABLE should change not only the name but +--echo # also the value for the last column of the table. +alter table t1 drop column i, add column k int default 0; +select * from t1; +--echo # Clean-up. +drop table t1; + + +--echo End of 5.1 tests + +# +# Bug #31031 ALTER TABLE regression in 5.0 +# +# The ALTER TABLE operation failed with +# ERROR 1089 (HY000): Incorrect sub part key; ... +# +CREATE TABLE t1(c CHAR(10), + i INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES('a',2),('b',4),('c',6); +ALTER TABLE t1 + DROP i, + ADD i INT UNSIGNED NOT NULL AUTO_INCREMENT, + AUTO_INCREMENT = 1; +DROP TABLE t1; + + +# +# Bug#50542 5.5.x doesn't check length of key prefixes: +# corruption and crash results +# +# This case is related to Bug#31031 (above) +# A statement where the index key is larger/wider than +# the column type, should cause an error +# +--error ER_WRONG_SUB_KEY +CREATE TABLE t1 (a CHAR(1), PRIMARY KEY (a(255))); + +# Test other variants of creating indices +CREATE TABLE t1 (a CHAR(1)); +# ALTER TABLE +--error ER_WRONG_SUB_KEY +ALTER TABLE t1 ADD PRIMARY KEY (a(20)); +--error ER_WRONG_SUB_KEY +ALTER TABLE t1 ADD KEY (a(20)); +# CREATE INDEX +--error ER_WRONG_SUB_KEY +CREATE UNIQUE INDEX i1 ON t1 (a(20)); +--error ER_WRONG_SUB_KEY +CREATE INDEX i2 ON t1 (a(20)); +# cleanup +DROP TABLE t1; + + +# +# Bug #45052 ALTER TABLE ADD COLUMN crashes server with multiple foreign key columns +# The alter table fails if 2 or more new fields added and +# also added a key with these fields +# +CREATE TABLE t1 (id int); +INSERT INTO t1 VALUES (1), (2); +ALTER TABLE t1 ADD COLUMN (f1 INT), ADD COLUMN (f2 INT), ADD KEY f2k(f2); +DROP TABLE t1; + + +--echo # +--echo # Test for bug #53820 "ALTER a MEDIUMINT column table causes full +--echo # table copy". +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (a INT, b MEDIUMINT); +INSERT INTO t1 VALUES (1, 1), (2, 2); +--echo # The below ALTER should not copy table and so no rows should +--echo # be shown as affected. +--enable_info +ALTER TABLE t1 CHANGE a id INT; +--disable_info +DROP TABLE t1; + + +--echo # +--echo # Bug#11754461 CANNOT ALTER TABLE WHEN KEY PREFIX TOO LONG +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS db1; +--enable_warnings + +CREATE DATABASE db1 CHARACTER SET utf8; +CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(100))); +ALTER TABLE db1.t1 ADD baz INT; + +DROP DATABASE db1; + + +--echo # Additional coverage for refactoring which is made as part +--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +--echo # to allow temp table operations". +--echo # +--echo # At some point the below test case failed on assertion. + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TEMPORARY TABLE t1 (i int) ENGINE=MyISAM; + +--error ER_ILLEGAL_HA +ALTER TABLE t1 DISCARD TABLESPACE; + +DROP TABLE t1; + + +--echo # +--echo # Bug#11938039 RE-EXECUTION OF FRM-ONLY ALTER TABLE WITH RENAME +--echo # CLAUSE FAILS OR ABORTS SERVER. +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int); +prepare stmt1 from 'alter table t1 alter column a set default 1, rename to t2'; +execute stmt1; +rename table t2 to t1; +--echo # The below statement should succeed and not emit error or abort server. +execute stmt1; +deallocate prepare stmt1; +drop table t2; + +--echo # +--echo # MDEV-8960 Can't refer the same column twice in one ALTER TABLE +--echo # + +CREATE TABLE t1 ( + `a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; + +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL, +ALTER COLUMN `consultant_id` DROP DEFAULT; + +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + `a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; + +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL, +ALTER COLUMN `consultant_id` SET DEFAULT 2; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + `a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; + +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL DEFAULT 2, +ALTER COLUMN `consultant_id` DROP DEFAULT; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + `a` int(11) DEFAULT NULL +) DEFAULT CHARSET=utf8; + +ALTER TABLE t1 ADD COLUMN `consultant_id` integer NOT NULL DEFAULT 2, +ALTER COLUMN `consultant_id` DROP DEFAULT, +MODIFY COLUMN `consultant_id` BIGINT; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# +# Test of ALTER TABLE IF [NOT] EXISTS +# + +CREATE TABLE t1 ( + id INT(11) NOT NULL, + x_param INT(11) DEFAULT NULL, + PRIMARY KEY (id) +) ENGINE=MYISAM; + +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS id INT, + ADD COLUMN IF NOT EXISTS lol INT AFTER id; +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS lol INT AFTER id; +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; + +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +ALTER TABLE t1 MODIFY IF EXISTS lol INT; + +DROP INDEX IF EXISTS x_param ON t1; +DROP INDEX IF EXISTS x_param ON t1; +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + id INT(11) NOT NULL, + x_param INT(11) DEFAULT NULL, + PRIMARY KEY (id) +) ENGINE=INNODB; + +CREATE TABLE t2 ( + id INT(11) NOT NULL) ENGINE=INNODB; + +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS id INT, + ADD COLUMN IF NOT EXISTS lol INT AFTER id; +ALTER TABLE t1 ADD COLUMN IF NOT EXISTS lol INT AFTER id; +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; +ALTER TABLE t1 DROP COLUMN IF EXISTS lol; + +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +ALTER TABLE t1 ADD KEY IF NOT EXISTS x_param(x_param); +ALTER TABLE t1 MODIFY IF EXISTS lol INT; + +DROP INDEX IF EXISTS x_param ON t1; +DROP INDEX IF EXISTS x_param ON t1; +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +CREATE INDEX IF NOT EXISTS x_param1 ON t1(x_param); +SHOW CREATE TABLE t1; + +ALTER TABLE t2 ADD FOREIGN KEY IF NOT EXISTS fk(id) REFERENCES t1(id); +ALTER TABLE t2 ADD FOREIGN KEY IF NOT EXISTS fk(id) REFERENCES t1(id); +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS fk; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS fk; +SHOW CREATE TABLE t2; +ALTER TABLE t2 ADD FOREIGN KEY (id) REFERENCES t1(id); +ALTER TABLE t2 ADD FOREIGN KEY IF NOT EXISTS t2_ibfk_1(id) REFERENCES t1(id); +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS t2_ibfk_1; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS t2_ibfk_1; +SHOW CREATE TABLE t2; + +DROP TABLE t2; +CREATE TABLE t2 ( + id INT(11) NOT NULL); +ALTER TABLE t2 ADD COLUMN a INT, ADD COLUMN IF NOT EXISTS a INT; +ALTER TABLE t2 ADD KEY k_id(id), ADD KEY IF NOT EXISTS k_id(id); +SHOW CREATE TABLE t2; +ALTER TABLE t2 DROP KEY k_id, DROP KEY IF EXISTS k_id; +ALTER TABLE t2 DROP COLUMN a, DROP COLUMN IF EXISTS a; +SHOW CREATE TABLE t2; + +DROP TABLE t2; +DROP TABLE t1; + +CREATE TABLE t1 ( + `transaction_id` int(11) NOT NULL DEFAULT '0', + KEY `transaction_id` (`transaction_id`)); +ALTER TABLE t1 DROP KEY IF EXISTS transaction_id, ADD PRIMARY KEY IF NOT EXISTS (transaction_id); +SHOW CREATE TABLE t1; + +DROP TABLE t1; + +--echo # Bug#11748057 (formerly known as 34972): ALTER TABLE statement doesn't +--echo # identify correct column name. +--echo # + +CREATE TABLE t1 (c1 int unsigned , c2 char(100) not null default ''); +ALTER TABLE t1 ADD c3 char(16) NOT NULL DEFAULT '' AFTER c2, + MODIFY c2 char(100) NOT NULL DEFAULT '' AFTER c1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # WL#5534 Online ALTER, Phase 1 +--echo # + +--echo # Single thread tests. +--echo # See innodb_mysql_sync.test for multi thread tests. + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1(a INT PRIMARY KEY, b INT) engine=InnoDB; +CREATE TABLE m1(a INT PRIMARY KEY, b INT) engine=MyISAM; +INSERT INTO t1 VALUES (1,1), (2,2); +INSERT INTO m1 VALUES (1,1), (2,2); + +--echo # +--echo # 1: Test ALGORITHM keyword +--echo # + +--echo # --enable_info allows us to see how many rows were updated +--echo # by ALTER TABLE. in-place will show 0 rows, while copy > 0. + +--enable_info +ALTER TABLE t1 ADD INDEX i1(b); +ALTER TABLE t1 ADD INDEX i2(b), ALGORITHM= DEFAULT; +ALTER TABLE t1 ADD INDEX i3(b), ALGORITHM= COPY; +ALTER TABLE t1 ADD INDEX i4(b), ALGORITHM= INPLACE; +--error ER_UNKNOWN_ALTER_ALGORITHM +ALTER TABLE t1 ADD INDEX i5(b), ALGORITHM= INVALID; + +ALTER TABLE m1 ENABLE KEYS; +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= DEFAULT; +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY; +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE; +--disable_info + +ALTER TABLE t1 DROP INDEX i1, DROP INDEX i2, DROP INDEX i3, DROP INDEX i4; + +--echo # +--echo # 2: Test ALGORITHM + old_alter_table +--echo # + +--enable_info +SET SESSION old_alter_table= 1; +ALTER TABLE t1 ADD INDEX i1(b); +ALTER TABLE t1 ADD INDEX i2(b), ALGORITHM= DEFAULT; +ALTER TABLE t1 ADD INDEX i3(b), ALGORITHM= COPY; +ALTER TABLE t1 ADD INDEX i4(b), ALGORITHM= INPLACE; +SET SESSION old_alter_table= 0; +--disable_info + +ALTER TABLE t1 DROP INDEX i1, DROP INDEX i2, DROP INDEX i3, DROP INDEX i4; + +--echo # +--echo # 3: Test unsupported in-place operation +--echo # + +ALTER TABLE t1 ADD COLUMN (c1 INT); +ALTER TABLE t1 ADD COLUMN (c2 INT), ALGORITHM= DEFAULT; +ALTER TABLE t1 ADD COLUMN (c3 INT), ALGORITHM= COPY; +ALTER TABLE t1 ADD COLUMN (c4 INT), ALGORITHM= INPLACE; + +ALTER TABLE t1 DROP COLUMN c1, DROP COLUMN c2, DROP COLUMN c3, DROP COLUMN c4; + +--echo # +--echo # 4: Test LOCK keyword +--echo # + +--enable_info +ALTER TABLE t1 ADD INDEX i1(b), LOCK= DEFAULT; +ALTER TABLE t1 ADD INDEX i2(b), LOCK= NONE; +ALTER TABLE t1 ADD INDEX i3(b), LOCK= SHARED; +ALTER TABLE t1 ADD INDEX i4(b), LOCK= EXCLUSIVE; +--error ER_UNKNOWN_ALTER_LOCK +ALTER TABLE t1 ADD INDEX i5(b), LOCK= INVALID; +--disable_info + +ALTER TABLE m1 ENABLE KEYS, LOCK= DEFAULT; +--error ER_ALTER_OPERATION_NOT_SUPPORTED +ALTER TABLE m1 ENABLE KEYS, LOCK= NONE; +--error ER_ALTER_OPERATION_NOT_SUPPORTED +ALTER TABLE m1 ENABLE KEYS, LOCK= SHARED; +ALTER TABLE m1 ENABLE KEYS, LOCK= EXCLUSIVE; + +ALTER TABLE t1 DROP INDEX i1, DROP INDEX i2, DROP INDEX i3, DROP INDEX i4; + +--echo # +--echo # 5: Test ALGORITHM + LOCK +--echo # + +--enable_info +ALTER TABLE t1 ADD INDEX i1(b), ALGORITHM= INPLACE, LOCK= NONE; +ALTER TABLE t1 ADD INDEX i2(b), ALGORITHM= INPLACE, LOCK= SHARED; +ALTER TABLE t1 ADD INDEX i3(b), ALGORITHM= INPLACE, LOCK= EXCLUSIVE; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +ALTER TABLE t1 ADD INDEX i4(b), ALGORITHM= COPY, LOCK= NONE; +ALTER TABLE t1 ADD INDEX i5(b), ALGORITHM= COPY, LOCK= SHARED; +ALTER TABLE t1 ADD INDEX i6(b), ALGORITHM= COPY, LOCK= EXCLUSIVE; + +--error ER_ALTER_OPERATION_NOT_SUPPORTED +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE, LOCK= NONE; +--error ER_ALTER_OPERATION_NOT_SUPPORTED +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE, LOCK= SHARED; +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= INPLACE, LOCK= EXCLUSIVE; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY, LOCK= NONE; +--error ER_ALTER_OPERATION_NOT_SUPPORTED +ALTER ONLINE TABLE m1 ADD COLUMN c int; +# This works because the lock will be SNW for the copy phase. +# It will still require exclusive lock for actually enabling keys. +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY, LOCK= SHARED; +ALTER TABLE m1 ENABLE KEYS, ALGORITHM= COPY, LOCK= EXCLUSIVE; +--disable_info + +DROP TABLE t1, m1; + +--echo # +--echo # 6: Possible deadlock involving thr_lock.c +--echo # + +CREATE TABLE t1(a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); + +START TRANSACTION; +INSERT INTO t1 VALUES (3,3); + +connect (con1, localhost, root); +--echo # Sending: +--send ALTER TABLE t1 DISABLE KEYS + +connection default; +--echo # Waiting until ALTER TABLE is blocked. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table metadata lock" AND + info = "ALTER TABLE t1 DISABLE KEYS"; +--source include/wait_condition.inc +UPDATE t1 SET b = 4; +COMMIT; + +connection con1; +--echo # Reaping: ALTER TABLE t1 DISABLE KEYS +--reap +disconnect con1; +--source include/wait_until_disconnected.inc + +connection default; +DROP TABLE t1; + +--echo # +--echo # 7: Which operations require copy and which can be done in-place? +--echo # +--echo # Test which ALTER TABLE operations are done in-place and +--echo # which operations are done using temporary table copy. +--echo # +--echo # --enable_info allows us to see how many rows were updated +--echo # by ALTER TABLE. in-place will show 0 rows, while copy > 0. +--echo # + +--disable_warnings +DROP TABLE IF EXISTS ti1, ti2, ti3, tm1, tm2, tm3; +--enable_warnings + +--echo # Single operation tests + +CREATE TABLE ti1(a INT NOT NULL, b INT, c INT) engine=InnoDB; +CREATE TABLE tm1(a INT NOT NULL, b INT, c INT) engine=MyISAM; +CREATE TABLE ti2(a INT PRIMARY KEY AUTO_INCREMENT, b INT, c INT) engine=InnoDB; +CREATE TABLE tm2(a INT PRIMARY KEY AUTO_INCREMENT, b INT, c INT) engine=MyISAM; +INSERT INTO ti1 VALUES (1,1,1), (2,2,2); +INSERT INTO ti2 VALUES (1,1,1), (2,2,2); +INSERT INTO tm1 VALUES (1,1,1), (2,2,2); +INSERT INTO tm2 VALUES (1,1,1), (2,2,2); + +--enable_info +ALTER TABLE ti1; +ALTER TABLE tm1; + +ALTER TABLE ti1 ADD COLUMN d VARCHAR(200); +ALTER TABLE tm1 ADD COLUMN d VARCHAR(200); +ALTER TABLE ti1 ADD COLUMN d2 VARCHAR(200); +ALTER TABLE tm1 ADD COLUMN d2 VARCHAR(200); +ALTER TABLE ti1 ADD COLUMN e ENUM('a', 'b') FIRST; +ALTER TABLE tm1 ADD COLUMN e ENUM('a', 'b') FIRST; +ALTER TABLE ti1 ADD COLUMN f INT AFTER a; +ALTER TABLE tm1 ADD COLUMN f INT AFTER a; + +ALTER TABLE ti1 ADD INDEX ii1(b); +ALTER TABLE tm1 ADD INDEX im1(b); +ALTER TABLE ti1 ADD UNIQUE INDEX ii2 (c); +ALTER TABLE tm1 ADD UNIQUE INDEX im2 (c); +ALTER TABLE ti1 ADD FULLTEXT INDEX ii3 (d); +ALTER TABLE tm1 ADD FULLTEXT INDEX im3 (d); +ALTER TABLE ti1 ADD FULLTEXT INDEX ii4 (d2); +ALTER TABLE tm1 ADD FULLTEXT INDEX im4 (d2); + +# Bug#14140038 INCONSISTENT HANDLING OF FULLTEXT INDEXES IN ALTER TABLE +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +ALTER TABLE ti1 ADD PRIMARY KEY(a), ALGORITHM=INPLACE; +ALTER TABLE ti1 ADD PRIMARY KEY(a); +ALTER TABLE tm1 ADD PRIMARY KEY(a); + +ALTER TABLE ti1 DROP INDEX ii3; +ALTER TABLE tm1 DROP INDEX im3; + +ALTER TABLE ti1 DROP COLUMN d2; +ALTER TABLE tm1 DROP COLUMN d2; + +ALTER TABLE ti1 ADD CONSTRAINT fi1 FOREIGN KEY (b) REFERENCES ti2(a); +ALTER TABLE tm1 ADD CONSTRAINT fm1 FOREIGN KEY (b) REFERENCES tm2(a); + +ALTER TABLE ti1 ALTER COLUMN b SET DEFAULT 1; +ALTER TABLE tm1 ALTER COLUMN b SET DEFAULT 1; +ALTER TABLE ti1 ALTER COLUMN b DROP DEFAULT; +ALTER TABLE tm1 ALTER COLUMN b DROP DEFAULT; + +# This will set both ALTER_COLUMN_NAME and COLUMN_DEFAULT_VALUE +ALTER TABLE ti1 CHANGE COLUMN f g INT; +ALTER TABLE tm1 CHANGE COLUMN f g INT; +ALTER TABLE ti1 CHANGE COLUMN g h VARCHAR(20); +ALTER TABLE tm1 CHANGE COLUMN g h VARCHAR(20); +ALTER TABLE ti1 MODIFY COLUMN e ENUM('a', 'b', 'c'); +ALTER TABLE tm1 MODIFY COLUMN e ENUM('a', 'b', 'c'); +ALTER TABLE ti1 MODIFY COLUMN e INT; +ALTER TABLE tm1 MODIFY COLUMN e INT; +# This will set both ALTER_COLUMN_ORDER and COLUMN_DEFAULT_VALUE +ALTER TABLE ti1 MODIFY COLUMN e INT AFTER h; +ALTER TABLE tm1 MODIFY COLUMN e INT AFTER h; +ALTER TABLE ti1 MODIFY COLUMN e INT FIRST; +ALTER TABLE tm1 MODIFY COLUMN e INT FIRST; +# This will set both ALTER_COLUMN_NOT_NULLABLE and COLUMN_DEFAULT_VALUE +--disable_info +# NULL -> NOT NULL only allowed INPLACE if strict sql_mode is on. +SET @orig_sql_mode = @@sql_mode; +SET @@sql_mode = 'STRICT_TRANS_TABLES'; +--enable_info +ALTER TABLE ti1 MODIFY COLUMN c INT NOT NULL; +--disable_info +SET @@sql_mode = @orig_sql_mode; +--enable_info +ALTER TABLE tm1 MODIFY COLUMN c INT NOT NULL; +# This will set both ALTER_COLUMN_NULLABLE and COLUMN_DEFAULT_VALUE +ALTER TABLE ti1 MODIFY COLUMN c INT NULL; +ALTER TABLE tm1 MODIFY COLUMN c INT NULL; +# This will set both ALTER_COLUMN_EQUAL_PACK_LENGTH and COLUMN_DEFAULT_VALUE +ALTER TABLE ti1 MODIFY COLUMN h VARCHAR(30); +ALTER TABLE tm1 MODIFY COLUMN h VARCHAR(30); +ALTER TABLE ti1 MODIFY COLUMN h VARCHAR(30) AFTER d; +ALTER TABLE tm1 MODIFY COLUMN h VARCHAR(30) AFTER d; + +ALTER TABLE ti1 DROP COLUMN h; +ALTER TABLE tm1 DROP COLUMN h; + +ALTER TABLE ti1 DROP INDEX ii2; +ALTER TABLE tm1 DROP INDEX im2; +ALTER TABLE ti1 DROP PRIMARY KEY; +ALTER TABLE tm1 DROP PRIMARY KEY; + +ALTER TABLE ti1 DROP FOREIGN KEY fi1; +ALTER TABLE tm1 DROP FOREIGN KEY fm1; + +ALTER TABLE ti1 RENAME TO ti3; +ALTER TABLE tm1 RENAME TO tm3; +ALTER TABLE ti3 RENAME TO ti1; +ALTER TABLE tm3 RENAME TO tm1; + +ALTER TABLE ti1 ORDER BY b; +ALTER TABLE tm1 ORDER BY b; + +ALTER TABLE ti1 CONVERT TO CHARACTER SET utf16; +ALTER TABLE tm1 CONVERT TO CHARACTER SET utf16; +ALTER TABLE ti1 DEFAULT CHARACTER SET utf8; +ALTER TABLE tm1 DEFAULT CHARACTER SET utf8; + +ALTER TABLE ti1 FORCE; +ALTER TABLE tm1 FORCE; + +ALTER TABLE ti1 AUTO_INCREMENT 3; +ALTER TABLE tm1 AUTO_INCREMENT 3; +ALTER TABLE ti1 AVG_ROW_LENGTH 10; +ALTER TABLE tm1 AVG_ROW_LENGTH 10; +ALTER TABLE ti1 CHECKSUM 1; +ALTER TABLE tm1 CHECKSUM 1; +ALTER TABLE ti1 COMMENT 'test'; +ALTER TABLE tm1 COMMENT 'test'; +ALTER TABLE ti1 MAX_ROWS 100; +ALTER TABLE tm1 MAX_ROWS 100; +ALTER TABLE ti1 MIN_ROWS 1; +ALTER TABLE tm1 MIN_ROWS 1; +ALTER TABLE ti1 PACK_KEYS 1; +ALTER TABLE tm1 PACK_KEYS 1; + +--disable_info +DROP TABLE ti1, ti2, tm1, tm2; + +--echo # Tests of >1 operation (InnoDB) + +CREATE TABLE ti1(a INT PRIMARY KEY AUTO_INCREMENT, b INT) engine=InnoDB; +INSERT INTO ti1(b) VALUES (1), (2); + +--enable_info +ALTER TABLE ti1 RENAME TO ti3, ADD INDEX ii1(b); + +ALTER TABLE ti3 DROP INDEX ii1, AUTO_INCREMENT 5; +--disable_info +INSERT INTO ti3(b) VALUES (5); +--enable_info +ALTER TABLE ti3 ADD INDEX ii1(b), AUTO_INCREMENT 7; +--disable_info +INSERT INTO ti3(b) VALUES (7); +SELECT * FROM ti3; + +DROP TABLE ti3; + +--echo # +--echo # 8: Scenario in which ALTER TABLE was returning an unwarranted +--echo # ER_ILLEGAL_HA error at some point during work on this WL. +--echo # + +CREATE TABLE tm1(i INT DEFAULT 1) engine=MyISAM; +ALTER TABLE tm1 ADD INDEX ii1(i), ALTER COLUMN i DROP DEFAULT; +DROP TABLE tm1; + +# +# MDEV-4435 Server crashes in my_strcasecmp_utf8 on ADD KEY IF NOT EXISTS with implicit name when the key exists. +# +create table if not exists t1 (i int); +alter table t1 add key (i); +alter table t1 add key if not exists (i); +DROP TABLE t1; + +# +# MDEV-4436 CHANGE COLUMN IF EXISTS does not work and throws wrong warning. +# +create table t1 (a int); +alter table t1 change column if exists a b bigint; +show create table t1; +DROP TABLE t1; + +# +# MDEV-4437 ALTER TABLE .. ADD UNIQUE INDEX IF NOT EXISTS causes syntax error. +# + +create table t1 (i int); +alter table t1 add unique index if not exists idx(i); +alter table t1 add unique index if not exists idx(i); +show create table t1; +DROP TABLE t1; + +# +# MDEV-8358 ADD PRIMARY KEY IF NOT EXISTS -> ERROR 1068 (42000): Multiple primary key +# + +CREATE TABLE t1 ( + `event_id` bigint(20) unsigned NOT NULL DEFAULT '0', + `market_id` bigint(20) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`event_id`,`market_id`) + ); +ALTER TABLE t1 ADD PRIMARY KEY IF NOT EXISTS event_id (event_id,market_id); +DROP TABLE t1; + +--echo # +--echo # MDEV-11126 Crash while altering persistent virtual column +--echo # + +CREATE TABLE `tab1` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `field2` set('option1','option2','option3','option4') NOT NULL, + `field3` set('option1','option2','option3','option4','option5') NOT NULL, + `field4` set('option1','option2','option3','option4') NOT NULL, + `field5` varchar(32) NOT NULL, + `field6` varchar(32) NOT NULL, + `field7` varchar(32) NOT NULL, + `field8` varchar(32) NOT NULL, + `field9` int(11) NOT NULL DEFAULT '1', + `field10` varchar(16) NOT NULL, + `field11` enum('option1','option2','option3') NOT NULL DEFAULT 'option1', + `v_col` varchar(128) AS (IF(field11='option1',CONCAT_WS(":","field1",field2,field3,field4,field5,field6,field7,field8,field9,field10), CONCAT_WS(":","field1",field11,field2,field3,field4,field5,field6,field7,field8,field9,field10))) PERSISTENT, + PRIMARY KEY (`id`) +) DEFAULT CHARSET=latin1; + +ALTER TABLE `tab1` CHANGE COLUMN v_col `v_col` varchar(128); +SHOW CREATE TABLE `tab1`; +ALTER TABLE `tab1` CHANGE COLUMN v_col `v_col` varchar(128) AS (IF(field11='option1',CONCAT_WS(":","field1",field2,field3,field4,field5,field6,field7,field8,field9,field10), CONCAT_WS(":","field1",field11,field2,field3,field4,field5,field6,field7,field8,field9,field10))) PERSISTENT; +SHOW CREATE TABLE `tab1`; +DROP TABLE `tab1`; + +--echo # +--echo # MDEV-11548 Reproducible server crash after the 2nd ALTER TABLE ADD FOREIGN KEY IF NOT EXISTS +--echo # + +CREATE TABLE t1 (id INT UNSIGNED NOT NULL PRIMARY KEY); +CREATE TABLE t2 (id1 INT UNSIGNED NOT NULL); + +ALTER TABLE t2 +ADD FOREIGN KEY IF NOT EXISTS (id1) + REFERENCES t1 (id); + +ALTER TABLE t2 +ADD FOREIGN KEY IF NOT EXISTS (id1) +REFERENCES t1 (id); + +DROP TABLE t2; +DROP TABLE t1; + +--echo # +--echo # MDEV-6390 CONVERT TO CHARACTER SET utf8 doesn't change DEFAULT CHARSET. +--echo # + +CREATE TABLE t1 (id int(11) NOT NULL, a int(11) NOT NULL, b int(11)) + ENGINE=InnoDB DEFAULT CHARSET=latin1; +SHOW CREATE TABLE t1; +ALTER TABLE t1 CONVERT TO CHARACTER SET utf8; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # MDEV-15308 +--echo # Assertion `ha_alter_info->alter_info->drop_list.elements > 0' failed +--echo # in ha_innodb::prepare_inplace_alter_table +--echo # + +CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; +ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN b; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; +ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN b; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INT, b INT, c INT, KEY(c)) ENGINE=InnoDB; +ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP COLUMN c; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INT, b INT, c INT, KEY c1(c)) ENGINE=InnoDB; +ALTER TABLE t1 DROP FOREIGN KEY IF EXISTS fk, DROP INDEX c1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; +ALTER TABLE t1 DROP INDEX IF EXISTS fk, DROP COLUMN IF EXISTS c; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # End of 10.0 tests +--echo # + +--echo # +--echo # MDEV-7374 : Losing connection to MySQL while running ALTER TABLE +--echo # +CREATE TABLE t1(i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8); +INSERT INTO t1 SELECT a.* FROM t1 a, t1 b, t1 c, t1 d, t1 e; +ALTER TABLE t1 MODIFY i FLOAT; +DROP TABLE t1; + +--echo # +--echo # MDEV-7816 ALTER with DROP INDEX and ADD INDEX .. COMMENT='comment2' ignores the new comment +--echo # +CREATE TABLE t1(a INT); +CREATE INDEX i1 ON t1(a) COMMENT 'comment1'; +ALTER TABLE t1 DROP INDEX i1, ADD INDEX i1(a) COMMENT 'comment2'; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo # +--echo # End of 10.1 tests +--echo # + +--echo # +--echo # MDEV-10421 duplicate CHECK CONSTRAINTs +--echo # +CREATE TABLE t1 (a INT, b INT) engine=myisam; +ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100); +--error ER_DUP_CONSTRAINT_NAME +ALTER TABLE t1 ADD CONSTRAINT `min` CHECK (a+b > 100); +ALTER TABLE t1 ADD CONSTRAINT IF NOT EXISTS `min` CHECK (a+b > 100); +ALTER TABLE t1 ADD CONSTRAINT `mini` CHECK (a+b > 100); +SHOW CREATE TABLE t1; +DROP TABLE t1; +--error ER_DUP_CONSTRAINT_NAME +CREATE TABLE t1(a INT, b INT, CONSTRAINT min check (a>5), + CONSTRAINT min check (b>5)); + +# +# MDEV-11114 Cannot drop column referenced by CHECK constraint +# +create table t1 (a int, b int, check(a>b)); +--error ER_BAD_FIELD_ERROR +alter table t1 drop column a; +--error ER_BAD_FIELD_ERROR +alter table t1 drop column b, add column b bigint first; +alter table t1 drop column a, drop constraint constraint_1; +show create table t1; +drop table t1; + +create table t1 (a int, b int, check(a>0)); +alter table t1 drop column a; +show create table t1; +drop table t1; + +create table t1 (a int, b int, check(a>0)); +alter table t1 drop column a, add column a bigint first; +show create table t1; +drop table t1; + +create table t1 (a int, b int, c int, unique(a)); +alter table t1 drop column a; +show create table t1; +drop table t1; + +create table t1 (a int, b int, c int, unique(a,b)); +--error ER_KEY_COLUMN_DOES_NOT_EXITS +alter table t1 drop column a; +alter table t1 drop column a, drop index a; +show create table t1; +drop table t1; + +# +# MDEV-14694 ALTER COLUMN IF EXISTS .. causes syntax error +# + +create table t1 (i int); +alter table t1 alter column if exists a set default 1; +alter table t1 alter column if exists a drop default; +show create table t1; +drop table t1; + +--echo # +--echo # MDEV-13508 Check that rename of columns changes defaults, virtual +--echo # columns and constraints +--echo # + +create table t1 (a int, b int, check(a>b)); +alter table t1 change column a b int, change column b a int; +show create table t1; +drop table t1; + +create table t1 (a int primary key, b int, c int default (a+b) check (a+b>0), + d int as (a+b), + key (b), + constraint test check (a+b > 1)); +alter table t1 change b new_b int not null, add column b char(1), add constraint new check (length(b) > 0); +show create table t1; +drop table t1; + ++--echo # ++--echo # MDEV-11071: Assertion `thd->transaction.stmt.is_empty()' failed ++--echo # in Locked_tables_list::unlock_locked_tables ++--echo # ++ ++CREATE TABLE t1 (d DATETIME DEFAULT CURRENT_TIMESTAMP, i INT) ENGINE=InnoDB; ++INSERT INTO t1 (i) VALUES (1),(1); ++LOCK TABLE t1 WRITE; ++--error ER_DUP_ENTRY ++ALTER TABLE t1 ADD UNIQUE(i); ++ ++# Cleanup ++UNLOCK TABLES; ++DROP TABLE t1; ++ ++ +--echo # +--echo # End of 10.2 tests +--echo # diff --cc sql/item.h index 10ce987e289,5ed45c69e96..0ee60afb3be --- a/sql/item.h +++ b/sql/item.h @@@ -4674,42 -4211,12 +4674,42 @@@ public also to make printing of items inherited from Item_sum uniform. */ virtual const char *func_name() const= 0; - virtual void fix_length_and_dec()= 0; + virtual bool fix_length_and_dec()= 0; bool const_item() const { return const_item_cache; } table_map used_tables() const { return used_tables_cache; } - Item* build_clone(THD *thd, MEM_ROOT *mem_root); + Item* build_clone(THD *thd); }; +class sp_head; +class sp_name; +struct st_sp_security_context; + +class Item_sp +{ +public: + Name_resolution_context *context; + sp_name *m_name; + sp_head *m_sp; + TABLE *dummy_table; + uchar result_buf[64]; + sp_rcontext *func_ctx; + MEM_ROOT sp_mem_root; + Query_arena *sp_query_arena; + + /* + The result field of the stored function. + */ + Field *sp_result_field; + Item_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name_arg); + Item_sp(THD *thd, Item_sp *item); + const char *func_name(THD *thd) const; + void cleanup(); + bool sp_check_access(THD *thd); + bool execute(THD *thd, bool *null_value, Item **args, uint arg_count); + bool execute_impl(THD *thd, Item **args, uint arg_count); + bool init_result_field(THD *thd, uint max_length, uint maybe_null, + bool *null_value, LEX_CSTRING *name); +}; class Item_ref :public Item_ident { diff --cc sql/item_cmpfunc.cc index 3034636dca3,b86c0079bce..37ec33c8358 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@@ -2053,30 -2108,35 +2059,31 @@@ void Item_func_between::fix_after_pullo eval_not_null_tables(NULL); } - void Item_func_between::fix_length_and_dec() + bool Item_func_between::fix_length_and_dec() { - THD *thd= current_thd; max_length= 1; - compare_as_dates= 0; /* As some compare functions are generated after sql_yacc, we have to check for out of memory conditions here */ if (!args[0] || !args[1] || !args[2]) - return; + return TRUE; - if (agg_cmp_type(&m_compare_type, args, 3)) + if (m_comparator.aggregate_for_comparison(Item_func_between::func_name(), + args, 3, true)) + { + DBUG_ASSERT(current_thd->is_error()); - return; + return TRUE; + } - m_comparator.type_handler()->Item_func_between_fix_length_and_dec(this); - if (m_compare_type == STRING_RESULT && - agg_arg_charsets_for_comparison(cmp_collation, args, 3)) - return TRUE; ++ return m_comparator.type_handler()-> ++ Item_func_between_fix_length_and_dec(this); +} - /* - When comparing as date/time, we need to convert non-temporal values - (e.g. strings) to MYSQL_TIME. - For this to work, we need to know what date/time type we compare - strings as. - */ - if (m_compare_type == TIME_RESULT) - compare_as_dates= find_date_time_item(thd, args, 3, 0, false); - /* See the comment for Item_func::convert_const_compared_to_int_field */ +bool Item_func_between::fix_length_and_dec_numeric(THD *thd) +{ + /* See the comment about the similar block in Item_bool_func2 */ if (args[0]->real_item()->type() == FIELD_ITEM && !thd->lex->is_ps_or_view_context_analysis()) { @@@ -2087,13 -2147,10 +2094,13 @@@ const bool cvt_arg1= convert_const_to_int(thd, field_item, &args[1]); const bool cvt_arg2= convert_const_to_int(thd, field_item, &args[2]); if (cvt_arg1 && cvt_arg2) - m_compare_type= INT_RESULT; // Works for all types. + { + // Works for all types + m_comparator.set_handler(&type_handler_longlong); + } } } - return false; + return FALSE; } @@@ -2604,7 -2730,9 +2611,9 @@@ Item_func_nullif::fix_length_and_dec( */ m_cache= args[0]->cmp_type() == STRING_RESULT ? new (thd->mem_root) Item_cache_str_for_nullif(thd, args[0]) : - Item_cache::get_cache(thd, args[0]); + args[0]->get_cache(thd); + if (!m_cache) + return TRUE; m_cache->setup(thd, args[0]); m_cache->store(args[0]); m_cache->set_used_tables(args[0]->used_tables()); @@@ -3029,129 -3169,86 +3040,129 @@@ static void propagate_and_change_item_t } -bool Item_func_case::fix_length_and_dec() +bool Item_func_case_simple::prepare_predicant_and_values(THD *thd, + uint *found_types, + bool nulls_equal) { - m_found_types= 0; - if (else_expr_num == -1 || args[else_expr_num]->maybe_null) - maybe_null= 1; - - /* - Aggregate all THEN and ELSE expression types - and collations when string result - */ - Item **rets= args + first_expr_num + 1 + nwhens; - uint nrets= nwhens + (else_expr_num != -1); - set_handler_by_field_type(agg_field_type(rets, nrets, true)); - - if (Item_func_case::result_type() == STRING_RESULT) + bool have_null= false; + uint type_cnt; + Type_handler_hybrid_field_type tmp; + uint ncases= when_count(); + add_predicant(this, 0); + for (uint i= 0 ; i < ncases; i++) { - if (count_string_result_length(Item_func_case::field_type(), rets, nrets)) - return TRUE; + if (nulls_equal ? + add_value("case..when", this, i + 1) : + add_value_skip_null("case..when", this, i + 1, &have_null)) + return true; } - else - fix_attributes(rets, nrets); + all_values_added(&tmp, &type_cnt, &m_found_types); +#ifndef DBUG_OFF + Predicant_to_list_comparator::debug_print(thd); +#endif + return false; +} + + - void Item_func_case_searched::fix_length_and_dec() ++bool Item_func_case_searched::fix_length_and_dec() +{ + THD *thd= current_thd; - aggregate_then_and_else_arguments(thd, when_count()); ++ return aggregate_then_and_else_arguments(thd, when_count()); +} + + - void Item_func_case_simple::fix_length_and_dec() ++bool Item_func_case_simple::fix_length_and_dec() +{ + THD *thd= current_thd; - if (!aggregate_then_and_else_arguments(thd, when_count() + 1)) - aggregate_switch_and_when_arguments(thd, false); ++ return (aggregate_then_and_else_arguments(thd, when_count() + 1) || ++ aggregate_switch_and_when_arguments(thd, false)); +} + + - void Item_func_decode_oracle::fix_length_and_dec() ++bool Item_func_decode_oracle::fix_length_and_dec() +{ + THD *thd= current_thd; - if (!aggregate_then_and_else_arguments(thd, when_count() + 1)) - aggregate_switch_and_when_arguments(thd, true); ++ return (aggregate_then_and_else_arguments(thd, when_count() + 1) || ++ aggregate_switch_and_when_arguments(thd, true)); +} + + +/* + Aggregate all THEN and ELSE expression types + and collations when string result - /* - Aggregate first expression and all WHEN expression types - and collations when string comparison - */ - if (first_expr_num != -1) - { - left_cmp_type= args[0]->cmp_type(); + @param THD - current thd + @param start - an element in args to start aggregating from +*/ +bool Item_func_case::aggregate_then_and_else_arguments(THD *thd, uint start) +{ + if (aggregate_for_result(func_name(), args + start, arg_count - start, true)) + return true; - if (!(m_found_types= collect_cmp_types(args, nwhens + 1))) - return TRUE; + if (fix_attributes(args + start, arg_count - start)) + return true; - Item *date_arg= 0; - if (m_found_types & (1U << TIME_RESULT)) - date_arg= find_date_time_item(current_thd, args, nwhens + 1, 0, true); + return false; +} - if (m_found_types & (1U << STRING_RESULT)) - { - /* - If we'll do string comparison, we also need to aggregate - character set and collation for first/WHEN items and - install converters for some of them to cmp_collation when necessary. - This is done because cmp_item compatators cannot compare - strings in two different character sets. - Some examples when we install converters: - 1. Converter installed for the first expression: +/* + Aggregate the predicant expression and all WHEN expression types + and collations when string comparison +*/ +bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd, + bool nulls_eq) +{ + uint ncases= when_count(); + m_found_types= 0; + if (prepare_predicant_and_values(thd, &m_found_types, nulls_eq)) + { + /* + If Predicant_to_list_comparator() fails to prepare components, + it must put an error into the diagnostics area. This is needed + to make fix_fields() catches such errors. + */ + DBUG_ASSERT(thd->is_error()); + return true; + } + + if (!(m_found_types= collect_cmp_types(args, ncases + 1))) + return true; - CASE latin1_item WHEN utf16_item THEN ... END + if (m_found_types & (1U << STRING_RESULT)) + { + /* + If we'll do string comparison, we also need to aggregate + character set and collation for first/WHEN items and + install converters for some of them to cmp_collation when necessary. + This is done because cmp_item compatators cannot compare + strings in two different character sets. + Some examples when we install converters: - is replaced to: + 1. Converter installed for the first expression: - CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END + CASE latin1_item WHEN utf16_item THEN ... END - 2. Converter installed for the left WHEN item: + is replaced to: - CASE utf16_item WHEN latin1_item THEN ... END + CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END - is replaced to: + 2. Converter installed for the left WHEN item: - CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END - */ - if (agg_arg_charsets_for_comparison(cmp_collation, args, nwhens + 1)) - return TRUE; - } + CASE utf16_item WHEN latin1_item THEN ... END - for (uint i= 0; i <= (uint)TIME_RESULT; i++) - { - if (m_found_types & (1U << i) && !cmp_items[i]) - { - DBUG_ASSERT((Item_result)i != ROW_RESULT); - if (!(cmp_items[i]= - cmp_item::get_comparator((Item_result)i, date_arg, - cmp_collation.collation))) - return TRUE; - } - } + is replaced to: + + CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END + */ + if (agg_arg_charsets_for_comparison(cmp_collation, args, ncases + 1)) + return true; } - return FALSE; + + if (make_unique_cmp_items(thd, cmp_collation.collation)) + return true; + + return false; } @@@ -4156,71 -4122,52 +4167,74 @@@ void Item_func_in::fix_after_pullout(st eval_not_null_tables(NULL); } -static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) + +bool Item_func_in::prepare_predicant_and_values(THD *thd, uint *found_types) { - return cs->coll->strnncollsp(cs, - (uchar *) x->ptr(),x->length(), - (uchar *) y->ptr(),y->length()); + uint type_cnt; + have_null= false; + + add_predicant(this, 0); + for (uint i= 1 ; i < arg_count; i++) + { + if (add_value_skip_null(Item_func_in::func_name(), this, i, &have_null)) + return true; + } + all_values_added(&m_comparator, &type_cnt, found_types); + arg_types_compatible= type_cnt < 2; + +#ifndef DBUG_OFF + Predicant_to_list_comparator::debug_print(thd); +#endif + return false; } -/* - Create 'array' for this IN predicate with the respect to its result type - and put values from <in value list> in 'array'. -*/ - void Item_func_in::fix_length_and_dec() -bool Item_func_in::create_array(THD *thd) ++bool Item_func_in::fix_length_and_dec() { - Item *date_arg= 0; + THD *thd= current_thd; + uint found_types; + m_comparator.set_handler(type_handler_varchar.type_handler_for_comparison()); + max_length= 1; - switch (m_compare_type) { - case STRING_RESULT: - array=new (thd->mem_root) in_string(thd, arg_count - 1, - (qsort2_cmp) srtcmp_in, - cmp_collation.collation); - break; - case INT_RESULT: - array= new (thd->mem_root) in_longlong(thd, arg_count - 1); - break; - case REAL_RESULT: - array= new (thd->mem_root) in_double(thd, arg_count - 1); - break; - case ROW_RESULT: - /* - The row comparator was created at the beginning but only DATETIME - items comparators were initialized. Call store_value() to setup - others. - */ - ((in_row*)array)->tmp.store_value(args[0]); - break; - case DECIMAL_RESULT: - array= new (thd->mem_root) in_decimal(thd, arg_count - 1); - break; - case TIME_RESULT: - date_arg= find_date_time_item(thd, args, arg_count, 0, true); - array= new (thd->mem_root) in_datetime(thd, date_arg, arg_count - 1); - break; + if (prepare_predicant_and_values(thd, &found_types)) + { + DBUG_ASSERT(thd->is_error()); // Must set error - return; ++ return TRUE; } - if (!array || thd->is_fatal_error) // OOM - return true; + + if (arg_types_compatible) // Bisection condition #1 + { - m_comparator.type_handler()-> - Item_func_in_fix_comparator_compatible_types(thd, this); ++ if (m_comparator.type_handler()-> ++ Item_func_in_fix_comparator_compatible_types(thd, this)) ++ return TRUE; + } + else + { + DBUG_ASSERT(m_comparator.cmp_type() != ROW_RESULT); - fix_for_scalar_comparison_using_cmp_items(thd, found_types); ++ if ( fix_for_scalar_comparison_using_cmp_items(thd, found_types)) ++ return TRUE; + } + + DBUG_EXECUTE_IF("Item_func_in", + push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, + ER_UNKNOWN_ERROR, "DBUG: types_compatible=%s bisect=%s", + arg_types_compatible ? "yes" : "no", + array != NULL ? "yes" : "no");); ++ return FALSE; +} + + +/** + Populate Item_func_in::array with constant not-NULL arguments and sort them. + + Sets "have_null" to true if some of the values appeared to be NULL. + Note, explicit NULLs were found during prepare_predicant_and_values(). + So "have_null" can already be true before the fix_in_vector() call. + Here we additionally catch implicit NULLs. +*/ +void Item_func_in::fix_in_vector() +{ + DBUG_ASSERT(array); uint j=0; for (uint i=1 ; i < arg_count ; i++) { @@@ -5710,7 -5714,7 +5725,8 @@@ Item_func_regexp_instr::fix_length_and_ re.init(cmp_collation.collation, 0); re.fix_owner(this, args[0], args[1]); + max_length= MY_INT32_NUM_DECIMAL_DIGITS; // See also Item_func_locate + return FALSE; } @@@ -6739,11 -6743,12 +6756,12 @@@ longlong Item_equal::val_int( } - void Item_equal::fix_length_and_dec() + bool Item_equal::fix_length_and_dec() { Item *item= get_first(NO_PARTICULAR_TAB, NULL); - eval_item= cmp_item::get_comparator(item->cmp_type(), item, - item->collation.collation); - return FALSE; + const Type_handler *handler= item->type_handler(); + eval_item= handler->make_cmp_item(current_thd, item->collation.collation); ++ return eval_item == NULL; } diff --cc sql/item_cmpfunc.h index 30d682f05aa,a59432058eb..c321b826ea4 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@@ -215,10 -198,9 +215,10 @@@ public Item_bool_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} Item_bool_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { } Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} + const Type_handler *type_handler() const { return &type_handler_long; } bool is_bool_type() { return true; } virtual CHARSET_INFO *compare_collation() const { return NULL; } - void fix_length_and_dec() { decimals=0; max_length=1; } + bool fix_length_and_dec() { decimals=0; max_length=1; return FALSE; } uint decimal_precision() const { return 1; } bool need_parentheses_in_default() { return true; } }; @@@ -903,13 -878,7 +903,13 @@@ public enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } enum precedence precedence() const { return BETWEEN_PRECEDENCE; } - void fix_length_and_dec(); + bool fix_length_and_dec(); + bool fix_length_and_dec_string(THD *) + { + return agg_arg_charsets_for_comparison(cmp_collation, args, 3); + } + bool fix_length_and_dec_temporal(THD *); + bool fix_length_and_dec_numeric(THD *); virtual void print(String *str, enum_query_type query_type); bool eval_not_null_tables(void *opt_arg); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); @@@ -950,13 -911,15 +950,15 @@@ public longlong val_int(); uint decimal_precision() const { return 1; } const char *func_name() const { return "strcmp"; } - void fix_length_and_dec() + bool fix_length_and_dec() { - agg_arg_charsets_for_comparison(cmp_collation, args, 2); - fix_char_length(2); // returns "1" or "0" or "-1" + if (agg_arg_charsets_for_comparison(cmp_collation, args, 2)) + return TRUE; + fix_char_length(2); + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_strcmp>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_strcmp>(thd, this); } }; @@@ -972,17 -935,15 +974,17 @@@ class Item_func_interval :public Item_l Item_row *row; bool use_decimal_comparison; interval_range *intervals; -public: - Item_func_interval(THD *thd, Item_row *a): - Item_int_func(thd, a), row(a), intervals(0) + bool check_arguments() const { - allowed_arg_cols= 0; // Fetch this value from first argument + return check_argument_types_like_args0(); } +public: + Item_func_interval(THD *thd, Item_row *a): + Item_long_func(thd, a), row(a), intervals(0) + { } bool fix_fields(THD *, Item **); longlong val_int(); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "interval"; } uint decimal_precision() const { return 2; } void print(String *str, enum_query_type query_type) @@@ -1006,12 -967,12 +1008,14 @@@ public longlong int_op(); String *str_op(String *); my_decimal *decimal_op(my_decimal *); - bool date_op(MYSQL_TIME *ltime,uint fuzzydate); + bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool time_op(MYSQL_TIME *ltime); - void fix_length_and_dec() + bool fix_length_and_dec() { - if (!aggregate_for_result(func_name(), args, arg_count, true)) - fix_attributes(args, arg_count); - set_handler_by_field_type(agg_field_type(args, arg_count, true)); ++ if (aggregate_for_result(func_name(), args, arg_count, true)) ++ return TRUE; + fix_attributes(args, arg_count); + return FALSE; } const char *func_name() const { return "coalesce"; } table_map not_null_tables() const { return 0; } @@@ -1024,49 -985,22 +1028,53 @@@ Case abbreviations that aggregate its result field type by two arguments: IFNULL(arg1, arg2) IF(switch, arg1, arg2) + NVL2(switch, arg1, arg2) */ -class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type +class Item_func_case_abbreviation2 :public Item_func_case_expression { protected: - void fix_length_and_dec2(Item **items) + bool fix_length_and_dec2(Item **items) { - if (!aggregate_for_result(func_name(), items, 2, true)) - fix_attributes(items, 2); - set_handler_by_field_type(agg_field_type(items, 2, true)); ++ if (aggregate_for_result(func_name(), items, 2, true)) ++ return TRUE; + fix_attributes(items, 2); + return FALSE; } - uint decimal_precision2(Item **args) const; + + void cache_type_info(const Item *source, bool maybe_null_arg) + { + Type_std_attributes::set(source); + set_handler(source->type_handler()); + maybe_null= maybe_null_arg; + } + - void fix_length_and_dec2_eliminate_null(Item **items) ++ bool fix_length_and_dec2_eliminate_null(Item **items) + { + // Let IF(cond, expr, NULL) and IF(cond, NULL, expr) inherit type from expr. + if (items[0]->type() == NULL_ITEM) + { + cache_type_info(items[1], true); + // If both arguments are NULL, make resulting type BINARY(0). + if (items[1]->type() == NULL_ITEM) + set_handler(&type_handler_string); + } + else if (items[1]->type() == NULL_ITEM) + { + cache_type_info(items[0], true); + } + else + { - fix_length_and_dec2(items); ++ if (fix_length_and_dec2(items)) ++ return TRUE; + } ++ return FALSE; + } + public: Item_func_case_abbreviation2(THD *thd, Item *a, Item *b): - Item_func_hybrid_field_type(thd, a, b) { } + Item_func_case_expression(thd, a, b) { } Item_func_case_abbreviation2(THD *thd, Item *a, Item *b, Item *c): - Item_func_hybrid_field_type(thd, a, b, c) { } + Item_func_case_expression(thd, a, b, c) { } }; @@@ -1079,80 -1013,44 +1087,82 @@@ public longlong int_op(); String *str_op(String *str); my_decimal *decimal_op(my_decimal *); - bool date_op(MYSQL_TIME *ltime,uint fuzzydate); + bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool time_op(MYSQL_TIME *ltime); - void fix_length_and_dec() + bool fix_length_and_dec() { - Item_func_case_abbreviation2::fix_length_and_dec2(args); + if (Item_func_case_abbreviation2::fix_length_and_dec2(args)) + return TRUE; maybe_null= args[1]->maybe_null; + return FALSE; } const char *func_name() const { return "ifnull"; } - Field *create_field_for_create_select(TABLE *table) - { return tmp_table_field_from_field_type(table, false, false); } table_map not_null_tables() const { return 0; } - uint decimal_precision() const + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_ifnull>(thd, this); } +}; + + +/** + Case abbreviations that have a switch argument and + two return arguments to choose from. Returns the value + of either of the two return arguments depending on the switch argument value. + + IF(switch, arg1, arg2) + NVL(switch, arg1, arg2) +*/ +class Item_func_case_abbreviation2_switch: public Item_func_case_abbreviation2 +{ +protected: + virtual Item *find_item() const= 0; + +public: + Item_func_case_abbreviation2_switch(THD *thd, Item *a, Item *b, Item *c) + :Item_func_case_abbreviation2(thd, a, b, c) + { } + + bool date_op(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + Datetime dt(current_thd, find_item(), fuzzydate); + return (null_value= dt.copy_to_mysql_time(ltime, mysql_timestamp_type())); + } + bool time_op(MYSQL_TIME *ltime) + { + return (null_value= Time(find_item()).copy_to_mysql_time(ltime)); + } + longlong int_op() { - return Item_func_case_abbreviation2::decimal_precision2(args); + return val_int_from_item(find_item()); + } + double real_op() + { + return val_real_from_item(find_item()); + } + my_decimal *decimal_op(my_decimal *decimal_value) + { + return val_decimal_from_item(find_item(), decimal_value); + } + String *str_op(String *str) + { + return val_str_from_item(find_item(), str); } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_ifnull>(thd, mem_root, this); } }; -class Item_func_if :public Item_func_case_abbreviation2 +class Item_func_if :public Item_func_case_abbreviation2_switch { +protected: + Item *find_item() const { return args[0]->val_bool() ? args[1] : args[2]; } + public: Item_func_if(THD *thd, Item *a, Item *b, Item *c): - Item_func_case_abbreviation2(thd, a, b, c) + Item_func_case_abbreviation2_switch(thd, a, b, c) {} - bool date_op(MYSQL_TIME *ltime, uint fuzzydate); - longlong int_op(); - double real_op(); - my_decimal *decimal_op(my_decimal *); - String *str_op(String *); bool fix_fields(THD *, Item **); - void fix_length_and_dec() - bool fix_length_and_dec(); - uint decimal_precision() const ++ bool fix_length_and_dec() { - fix_length_and_dec2_eliminate_null(args + 1); - return Item_func_case_abbreviation2::decimal_precision2(args + 1); ++ return fix_length_and_dec2_eliminate_null(args + 1); } const char *func_name() const { return "if"; } bool eval_not_null_tables(void *opt_arg); @@@ -1164,26 -1062,7 +1174,26 @@@ private }; -class Item_func_nullif :public Item_func_hybrid_field_type +class Item_func_nvl2 :public Item_func_case_abbreviation2_switch +{ +protected: + Item *find_item() const { return args[0]->is_null() ? args[2] : args[1]; } + +public: + Item_func_nvl2(THD *thd, Item *a, Item *b, Item *c): + Item_func_case_abbreviation2_switch(thd, a, b, c) + {} + const char *func_name() const { return "nvl2"; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - fix_length_and_dec2_eliminate_null(args + 1); ++ return fix_length_and_dec2_eliminate_null(args + 1); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_nvl2>(thd, this); } +}; + + +class Item_func_nullif :public Item_func_case_expression { Arg_comparator cmp; /* @@@ -1236,8 -1114,9 +1246,8 @@@ public longlong int_op(); String *str_op(String *str); my_decimal *decimal_op(my_decimal *); - void fix_length_and_dec(); + bool fix_length_and_dec(); bool walk(Item_processor processor, bool walk_subquery, void *arg); - uint decimal_precision() const { return args[2]->decimal_precision(); } const char *func_name() const { return "nullif"; } void print(String *str, enum_query_type query_type); void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, @@@ -2120,115 -1579,28 +2130,115 @@@ public table_map not_null_tables() const { return 0; } const char *func_name() const { return "case"; } enum precedence precedence() const { return BETWEEN_PRECEDENCE; } - virtual void print(String *str, enum_query_type query_type); - Item *find_item(String *str); CHARSET_INFO *compare_collation() const { return cmp_collation.collation; } - void cleanup(); - Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond); bool need_parentheses_in_default() { return true; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_case>(thd, mem_root, this); } - Item *build_clone(THD *thd, MEM_ROOT *mem_root) +}; + + +/* + CASE WHEN cond THEN res [WHEN cond THEN res...] [ELSE res] END + + Searched CASE checks all WHEN expressions one after another. + When some WHEN expression evaluated to TRUE then the + value of the corresponding THEN expression is returned. +*/ +class Item_func_case_searched: public Item_func_case +{ + uint when_count() const { return arg_count / 2; } + bool with_else() const { return arg_count % 2; } + Item **else_expr_addr() const { return with_else() ? &args[arg_count - 1] : 0; } +public: + Item_func_case_searched(THD *thd, List<Item> &list) + :Item_func_case(thd, list) { - Item_func_case *clone= (Item_func_case *) Item_func::build_clone(thd, mem_root); - if (clone) - { - clone->case_item= 0; - bzero(&clone->cmp_items, sizeof(cmp_items)); - } + DBUG_ASSERT(arg_count >= 2); + reorder_args(0); + } + void print(String *str, enum_query_type query_type); - void fix_length_and_dec(); ++ bool fix_length_and_dec(); + Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) + { + // None of the arguments are in a comparison context + Item_args::propagate_equal_fields(thd, Context_identity(), cond); + return this; + } + Item *find_item(); + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_case_searched>(thd, this); } +}; + + +/* + CASE pred WHEN value THEN res [WHEN value THEN res...] [ELSE res] END + + When the predicant expression is specified then it is compared to each WHEN + expression individually. When an equal WHEN expression is found + the corresponding THEN expression is returned. + In order to do correct comparisons several comparators are used. One for + each result type. Different result types that are used in particular + CASE ... END expression are collected in the fix_length_and_dec() member + function and only comparators for there result types are used. +*/ +class Item_func_case_simple: public Item_func_case, + public Predicant_to_list_comparator +{ +protected: + uint m_found_types; + uint when_count() const { return (arg_count - 1) / 2; } + bool with_else() const { return arg_count % 2 == 0; } + Item **else_expr_addr() const { return with_else() ? &args[arg_count - 1] : 0; } + bool aggregate_switch_and_when_arguments(THD *thd, bool nulls_equal); + bool prepare_predicant_and_values(THD *thd, uint *found_types, + bool nulls_equal); +public: + Item_func_case_simple(THD *thd, List<Item> &list) + :Item_func_case(thd, list), + Predicant_to_list_comparator(thd, arg_count), + m_found_types(0) + { + DBUG_ASSERT(arg_count >= 3); + reorder_args(1); + } + void cleanup() + { + DBUG_ENTER("Item_func_case_simple::cleanup"); + Item_func::cleanup(); + Predicant_to_list_comparator::cleanup(); + DBUG_VOID_RETURN; + } + void print(String *str, enum_query_type query_type); - void fix_length_and_dec(); ++ bool fix_length_and_dec(); + Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond); + Item *find_item(); + Item *build_clone(THD *thd) + { + Item_func_case_simple *clone= (Item_func_case_simple *) + Item_func_case::build_clone(thd); + uint ncases= when_count(); + if (clone && clone->Predicant_to_list_comparator::init_clone(thd, ncases)) + return NULL; return clone; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_case_simple>(thd, this); } +}; + + +class Item_func_decode_oracle: public Item_func_case_simple +{ +public: + Item_func_decode_oracle(THD *thd, List<Item> &list) + :Item_func_case_simple(thd, list) + { } + const char *func_name() const { return "decode_oracle"; } + void print(String *str, enum_query_type query_type); - void fix_length_and_dec(); ++ bool fix_length_and_dec(); + Item *find_item(); + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_decode_oracle>(thd, this); } }; + /* The Item_func_in class implements in_expr IN (<in value list>) @@@ -2298,52 -1642,23 +2308,52 @@@ public and can be used safely as comparisons for key conditions */ bool arg_types_compatible; - Item_result left_cmp_type; - cmp_item *cmp_items[6]; /* One cmp_item for each result type */ + + TABLE_LIST *emb_on_expr_nest; Item_func_in(THD *thd, List<Item> &list): - Item_func_opt_neg(thd, list), array(0), have_null(0), - arg_types_compatible(FALSE) - { - bzero(&cmp_items, sizeof(cmp_items)); - allowed_arg_cols= 0; // Fetch this value from first argument - } + Item_func_opt_neg(thd, list), + Predicant_to_list_comparator(thd, arg_count - 1), + transform_into_subq(false), + array(0), have_null(0), + arg_types_compatible(FALSE), emb_on_expr_nest(0) + { } longlong val_int(); bool fix_fields(THD *, Item **); - void fix_length_and_dec(); - bool create_array(THD *thd); + bool fix_length_and_dec(); + bool compatible_types_scalar_bisection_possible() + { + DBUG_ASSERT(m_comparator.cmp_type() != ROW_RESULT); + return all_items_are_consts(args + 1, arg_count - 1); // Bisection #2 + } + bool compatible_types_row_bisection_possible() + { + DBUG_ASSERT(m_comparator.cmp_type() == ROW_RESULT); + return all_items_are_consts(args + 1, arg_count - 1) && // Bisection #2 + ((is_top_level_item() && !negated) || // Bisection #3 + (!list_contains_null() && !args[0]->maybe_null)); // Bisection #4 + } + bool agg_all_arg_charsets_for_comparison() + { + return agg_arg_charsets_for_comparison(cmp_collation, args, arg_count); + } + void fix_in_vector(); + bool value_list_convert_const_to_int(THD *thd); + bool fix_for_scalar_comparison_using_bisection(THD *thd) + { + array= m_comparator.type_handler()->make_in_vector(thd, this, arg_count - 1); + if (!array) // OOM + return true; + fix_in_vector(); + return false; + } + bool fix_for_scalar_comparison_using_cmp_items(THD *thd, uint found_types); + + bool fix_for_row_comparison_using_cmp_items(THD *thd); + bool fix_for_row_comparison_using_bisection(THD *thd); + void cleanup() { - uint i; DBUG_ENTER("Item_func_in::cleanup"); Item_int_func::cleanup(); delete array; @@@ -2817,14 -2114,14 +2831,14 @@@ public } longlong val_int(); bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "regexp"; } enum precedence precedence() const { return CMP_PRECEDENCE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_regex>(thd, mem_root, this); } - Item *build_clone(THD *thd, MEM_ROOT *mem_root) + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_regex>(thd, this); } + Item *build_clone(THD *thd) { - Item_func_regex *clone= (Item_func_regex*) Item_bool_func::build_clone(thd, mem_root); + Item_func_regex *clone= (Item_func_regex*) Item_bool_func::build_clone(thd); if (clone) clone->re.reset(); return clone; @@@ -2867,10 -2152,10 +2881,10 @@@ public } longlong val_int(); bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "regexp_instr"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_regexp_instr>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_regexp_instr>(thd, this); } }; diff --cc sql/item_func.cc index 567c813de3c,4bdb18ad95a..5693484ad3b --- a/sql/item_func.cc +++ b/sql/item_func.cc @@@ -372,13 -234,10 +372,12 @@@ Item_func::fix_fields(THD *thd, Item ** with_window_func= with_window_func || item->with_window_func; with_field= with_field || item->with_field; used_tables_and_const_cache_join(item); - with_subselect|= item->has_subquery(); + m_with_subquery|= item->with_subquery(); } } + if (check_arguments()) + return true; - fix_length_and_dec(); - if (unlikely(thd->is_error())) // An error inside fix_length_and_dec occurred + if (fix_length_and_dec()) return TRUE; fixed= 1; return FALSE; @@@ -762,10 -732,12 +761,12 @@@ String *Item_int_func::val_str(String * } - void Item_func_connection_id::fix_length_and_dec() + bool Item_func_connection_id::fix_length_and_dec() { - Item_long_func::fix_length_and_dec(); - if (Item_int_func::fix_length_and_dec()) ++ if (Item_long_func::fix_length_and_dec()) + return TRUE; max_length= 10; + return FALSE; } @@@ -792,19 -796,44 +793,19 @@@ bool Item_num_op::fix_type_handler(cons } - void Item_func_plus::fix_length_and_dec(void) -/** - Set result type for a numeric function of one argument - (can be also used by a numeric function of many arguments, if the result - type depends only on the first argument) -*/ - -bool Item_func_num1::fix_length_and_dec() ++bool Item_func_plus::fix_length_and_dec(void) { - DBUG_ENTER("Item_func_num1::fix_length_and_dec"); + DBUG_ENTER("Item_func_plus::fix_length_and_dec"); DBUG_PRINT("info", ("name %s", func_name())); - // Note, cast_to_int_type() can return TIME_RESULT - switch (args[0]->cast_to_int_type()) { - case INT_RESULT: - set_handler_by_result_type(INT_RESULT); - max_length= args[0]->max_length; - unsigned_flag= args[0]->unsigned_flag; - break; - case STRING_RESULT: - case REAL_RESULT: - set_handler_by_result_type(REAL_RESULT); - decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC - max_length= float_length(decimals); - break; - case TIME_RESULT: - case DECIMAL_RESULT: - set_handler_by_result_type(DECIMAL_RESULT); - decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC - max_length= args[0]->max_length; - break; - case ROW_RESULT: - DBUG_ASSERT(0); - } - DBUG_PRINT("info", ("Type: %s", - (result_type() == REAL_RESULT ? "REAL_RESULT" : - result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" : - result_type() == INT_RESULT ? "INT_RESULT" : - "--ILLEGAL!!!--"))); + const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_plus; + DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_for_result;); + DBUG_ASSERT(aggregator->is_commutative()); - if (!fix_type_handler(aggregator)) - { - Item_func_plus::type_handler()->Item_func_plus_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - } - DBUG_VOID_RETURN; ++ if (fix_type_handler(aggregator)) ++ DBUG_RETURN(TRUE); ++ if (Item_func_plus::type_handler()->Item_func_plus_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); ++ DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); + DBUG_RETURN(FALSE); } @@@ -1316,22 -1423,9 +1317,22 @@@ void Item_func_minus::fix_unsigned_flag if (unsigned_flag && (current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION)) unsigned_flag=0; - return FALSE; +} + + - void Item_func_minus::fix_length_and_dec() ++bool Item_func_minus::fix_length_and_dec() +{ + DBUG_ENTER("Item_func_minus::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); + const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_minus; + DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_non_commutative_test;); + DBUG_ASSERT(!aggregator->is_commutative()); - if (!fix_type_handler(aggregator)) - { - Item_func_minus::type_handler()->Item_func_minus_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - } - DBUG_VOID_RETURN; ++ if (fix_type_handler(aggregator)) ++ DBUG_RETURN(TRUE); ++ if (Item_func_minus::type_handler()->Item_func_minus_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); ++ DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); ++ DBUG_RETURN(FALSE); } @@@ -1551,22 -1650,6 +1552,22 @@@ void Item_func_mul::result_precision( } - void Item_func_mul::fix_length_and_dec(void) ++bool Item_func_mul::fix_length_and_dec(void) +{ + DBUG_ENTER("Item_func_mul::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); + const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_mul; + DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_for_result;); + DBUG_ASSERT(aggregator->is_commutative()); - if (!fix_type_handler(aggregator)) - { - Item_func_mul::type_handler()->Item_func_mul_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - } - DBUG_VOID_RETURN; ++ if (fix_type_handler(aggregator)) ++ DBUG_RETURN(TRUE); ++ if (Item_func_mul::type_handler()->Item_func_mul_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); ++ DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); ++ DBUG_RETURN(FALSE); +} + + double Item_func_div::real_op() { DBUG_ASSERT(fixed == 1); @@@ -1634,46 -1723,43 +1635,46 @@@ void Item_func_div::result_precision( } +void Item_func_div::fix_length_and_dec_double(void) +{ + Item_num_op::fix_length_and_dec_double(); + decimals= MY_MAX(args[0]->decimals, args[1]->decimals) + prec_increment; + set_if_smaller(decimals, NOT_FIXED_DEC); + uint tmp= float_length(decimals); + if (decimals == NOT_FIXED_DEC) + max_length= tmp; + else + { + max_length=args[0]->max_length - args[0]->decimals + decimals; + set_if_smaller(max_length, tmp); + } +} + + +void Item_func_div::fix_length_and_dec_int(void) +{ + set_handler(&type_handler_newdecimal); + DBUG_PRINT("info", ("Type changed: %s", type_handler()->name().ptr())); + Item_num_op::fix_length_and_dec_decimal(); +} + + - void Item_func_div::fix_length_and_dec(void) + bool Item_func_div::fix_length_and_dec() { DBUG_ENTER("Item_func_div::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); prec_increment= current_thd->variables.div_precincrement; - if (Item_num_op::fix_length_and_dec()) - DBUG_RETURN(TRUE); - switch (Item_func_div::result_type()) { - case REAL_RESULT: - { - decimals=MY_MAX(args[0]->decimals,args[1]->decimals)+prec_increment; - set_if_smaller(decimals, NOT_FIXED_DEC); - uint tmp=float_length(decimals); - if (decimals == NOT_FIXED_DEC) - max_length= tmp; - else - { - max_length=args[0]->max_length - args[0]->decimals + decimals; - set_if_smaller(max_length,tmp); - } - break; - } - case INT_RESULT: - set_handler_by_result_type(DECIMAL_RESULT); - DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); - result_precision(); - break; - case DECIMAL_RESULT: - result_precision(); - fix_decimals(); - break; - case STRING_RESULT: - case ROW_RESULT: - case TIME_RESULT: - DBUG_ASSERT(0); - } maybe_null= 1; // devision by zero + + const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_div; + DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_non_commutative_test;); + DBUG_ASSERT(!aggregator->is_commutative()); - if (!fix_type_handler(aggregator)) - { - Item_func_div::type_handler()->Item_func_div_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - } - DBUG_VOID_RETURN; ++ if (fix_type_handler(aggregator)) ++ DBUG_RETURN(TRUE); ++ if (Item_func_div::type_handler()->Item_func_div_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); ++ DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); + DBUG_RETURN(FALSE); } @@@ -1843,20 -1930,13 +1845,20 @@@ void Item_func_mod::result_precision( } - void Item_func_mod::fix_length_and_dec() + bool Item_func_mod::fix_length_and_dec() { - if (Item_num_op::fix_length_and_dec()) - return true; - maybe_null= 1; - unsigned_flag= args[0]->unsigned_flag; - return false; + DBUG_ENTER("Item_func_mod::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); + maybe_null= true; // division by zero + const Type_aggregator *aggregator= &type_handler_data->m_type_aggregator_for_mod; + DBUG_EXECUTE_IF("num_op", aggregator= &type_handler_data->m_type_aggregator_non_commutative_test;); + DBUG_ASSERT(!aggregator->is_commutative()); - if (!fix_type_handler(aggregator)) - { - Item_func_mod::type_handler()->Item_func_mod_fix_length_and_dec(this); - DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - } - DBUG_VOID_RETURN; ++ if (fix_type_handler(aggregator)) ++ DBUG_RETURN(TRUE); ++ if (Item_func_mod::type_handler()->Item_func_mod_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); ++ DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); ++ DBUG_RETURN(FALSE); } @@@ -1929,38 -2012,8 +1931,40 @@@ void Item_func_neg::fix_length_and_dec_ DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); } } - unsigned_flag= 0; + unsigned_flag= false; +} + + +void Item_func_neg::fix_length_and_dec_double() +{ + set_handler(&type_handler_double); + decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC + max_length= args[0]->max_length + 1; + // Limit length with something reasonable + uint32 mlen= type_handler()->max_display_length(this); + set_if_smaller(max_length, mlen); + unsigned_flag= false; +} + + +void Item_func_neg::fix_length_and_dec_decimal() +{ + set_handler(&type_handler_newdecimal); + decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC + max_length= args[0]->max_length + 1; + unsigned_flag= false; +} + + - void Item_func_neg::fix_length_and_dec() ++bool Item_func_neg::fix_length_and_dec() +{ + DBUG_ENTER("Item_func_neg::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); - args[0]->cast_to_int_type_handler()->Item_func_neg_fix_length_and_dec(this); ++ if (args[0]->cast_to_int_type_handler()-> ++ Item_func_neg_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); + DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } @@@ -1999,50 -2052,23 +2003,51 @@@ my_decimal *Item_func_abs::decimal_op(m return 0; } - +void Item_func_abs::fix_length_and_dec_int() +{ + max_length= args[0]->max_length; + unsigned_flag= args[0]->unsigned_flag; + set_handler(type_handler_long_or_longlong()); +} + -bool Item_func_abs::fix_length_and_dec() +void Item_func_abs::fix_length_and_dec_double() { - if (Item_func_num1::fix_length_and_dec()) - return TRUE; + set_handler(&type_handler_double); + decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC + max_length= float_length(decimals); unsigned_flag= args[0]->unsigned_flag; - return FALSE; } -/** Gateway to natural LOG function. */ -double Item_func_ln::val_real() +void Item_func_abs::fix_length_and_dec_decimal() { - DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); - if ((null_value= args[0]->null_value)) - return 0.0; + set_handler(&type_handler_newdecimal); + decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC + max_length= args[0]->max_length; + unsigned_flag= args[0]->unsigned_flag; +} + + - void Item_func_abs::fix_length_and_dec() ++bool Item_func_abs::fix_length_and_dec() +{ + DBUG_ENTER("Item_func_abs::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); - args[0]->cast_to_int_type_handler()->Item_func_abs_fix_length_and_dec(this); ++ if (args[0]->cast_to_int_type_handler()-> ++ Item_func_abs_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); + DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - DBUG_VOID_RETURN; ++ DBUG_RETURN(FALSE); +} + + +/** Gateway to natural LOG function. */ +double Item_func_ln::val_real() +{ + DBUG_ASSERT(fixed == 1); + double value= args[0]->val_real(); + if ((null_value= args[0]->null_value)) + return 0.0; if (value <= 0.0) { signal_divide_by_null(); @@@ -2274,38 -2303,42 +2279,39 @@@ void Item_func_int_val::fix_length_and_ set_if_smaller(max_length,tmp); decimals= 0; - // Note, cast_to_int_type() can return TIME_RESULT - switch (args[0]->cast_to_int_type()) + /* + -2 because in most high position can't be used any digit for longlong + and one position for increasing value during operation + */ + if (args[0]->max_length - args[0]->decimals >= DECIMAL_LONGLONG_DIGITS - 2) { - case STRING_RESULT: - case REAL_RESULT: - set_handler_by_result_type(REAL_RESULT); - max_length= float_length(decimals); - break; - case INT_RESULT: - case TIME_RESULT: - case DECIMAL_RESULT: - /* - -2 because in most high position can't be used any digit for longlong - and one position for increasing value during operation - */ - if ((args[0]->max_length - args[0]->decimals) >= - (DECIMAL_LONGLONG_DIGITS - 2)) - { - set_handler_by_result_type(DECIMAL_RESULT); - } - else - { - unsigned_flag= args[0]->unsigned_flag; - set_handler_by_result_type(INT_RESULT); - } - break; - case ROW_RESULT: - DBUG_ASSERT(0); + set_handler(&type_handler_newdecimal); + } + else + { + unsigned_flag= args[0]->unsigned_flag; + set_handler(type_handler_long_or_longlong()); } - DBUG_PRINT("info", ("Type: %s", - (result_type() == REAL_RESULT ? "REAL_RESULT" : - result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" : - result_type() == INT_RESULT ? "INT_RESULT" : - "--ILLEGAL!!!--"))); +} + +void Item_func_int_val::fix_length_and_dec_double() +{ + set_handler(&type_handler_double); + max_length= float_length(0); + decimals= 0; +} + + - void Item_func_int_val::fix_length_and_dec() ++bool Item_func_int_val::fix_length_and_dec() +{ + DBUG_ENTER("Item_func_int_val::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); - args[0]->cast_to_int_type_handler()-> - Item_func_int_val_fix_length_and_dec(this); ++ if (args[0]->cast_to_int_type_handler()-> ++ Item_func_int_val_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); + DBUG_PRINT("info", ("Type: %s", type_handler()->name().ptr())); - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } @@@ -2403,92 -2436,86 +2409,91 @@@ my_decimal *Item_func_floor::decimal_op } -bool Item_func_round::fix_length_and_dec() +void Item_func_round::fix_length_and_dec_decimal(uint decimals_to_set) { - int decimals_to_set; - longlong val1; - bool val1_unsigned; - + int decimals_delta= args[0]->decimals - decimals_to_set; + int length_increase= (decimals_delta <= 0 || truncate) ? 0 : 1; + int precision= args[0]->decimal_precision() + length_increase - + decimals_delta; + DBUG_ASSERT(decimals_to_set <= DECIMAL_MAX_SCALE); + set_handler(&type_handler_newdecimal); + unsigned_flag= args[0]->unsigned_flag; + decimals= decimals_to_set; + max_length= my_decimal_precision_to_length_no_truncation(precision, + decimals, + unsigned_flag); +} + +void Item_func_round::fix_length_and_dec_double(uint decimals_to_set) +{ + set_handler(&type_handler_double); unsigned_flag= args[0]->unsigned_flag; - if (!args[1]->const_item()) + decimals= decimals_to_set; + max_length= float_length(decimals_to_set); +} + + +void Item_func_round::fix_arg_decimal() +{ + if (args[1]->const_item()) { - decimals= args[0]->decimals; - max_length= float_length(decimals); - if (args[0]->result_type() == DECIMAL_RESULT) - { - max_length++; - set_handler_by_result_type(DECIMAL_RESULT); - } + uint dec= (uint) args[1]->val_uint_from_val_int(DECIMAL_MAX_SCALE); + if (args[1]->null_value) + fix_length_and_dec_double(NOT_FIXED_DEC); else - set_handler_by_result_type(REAL_RESULT); - return FALSE; + fix_length_and_dec_decimal(dec); + } + else + { + set_handler(&type_handler_newdecimal); + unsigned_flag= args[0]->unsigned_flag; + decimals= args[0]->decimals; + max_length= float_length(args[0]->decimals) + 1; } +} - val1= args[1]->val_int(); - if ((null_value= args[1]->null_value)) - return FALSE; - val1_unsigned= args[1]->unsigned_flag; - if (val1 < 0) - decimals_to_set= val1_unsigned ? INT_MAX : 0; +void Item_func_round::fix_arg_double() +{ + if (args[1]->const_item()) + { + uint dec= (uint) args[1]->val_uint_from_val_int(NOT_FIXED_DEC); + fix_length_and_dec_double(args[1]->null_value ? NOT_FIXED_DEC : dec); + } else - decimals_to_set= (val1 > INT_MAX) ? INT_MAX : (int) val1; + fix_length_and_dec_double(args[0]->decimals); +} + - if (args[0]->decimals == NOT_FIXED_DEC) +void Item_func_round::fix_arg_int() +{ + if (args[1]->const_item()) { - decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC); - max_length= float_length(decimals); - set_handler_by_result_type(REAL_RESULT); - return FALSE; - } - - switch (args[0]->result_type()) { - case REAL_RESULT: - case STRING_RESULT: - set_handler_by_result_type(REAL_RESULT); - decimals= MY_MIN(decimals_to_set, NOT_FIXED_DEC); - max_length= float_length(decimals); - break; - case INT_RESULT: - if ((!decimals_to_set && truncate) || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS)) + longlong val1= args[1]->val_int(); + bool val1_is_negative= val1 < 0 && !args[1]->unsigned_flag; + uint decimals_to_set= val1_is_negative ? + 0 : (uint) MY_MIN(val1, DECIMAL_MAX_SCALE); + if (args[1]->null_value) + fix_length_and_dec_double(NOT_FIXED_DEC); + else if ((!decimals_to_set && truncate) || + args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS) { - int length_can_increase= MY_TEST(!truncate && (val1 < 0) && - !val1_unsigned); + // Length can increase in some cases: ROUND(9,-1) -> 10 + int length_can_increase= MY_TEST(!truncate && val1_is_negative); max_length= args[0]->max_length + length_can_increase; - /* Here we can keep INT_RESULT */ - set_handler_by_result_type(INT_RESULT); + // Here we can keep INT_RESULT + unsigned_flag= args[0]->unsigned_flag; decimals= 0; - break; + set_handler(type_handler_long_or_longlong()); } - /* fall through */ - case DECIMAL_RESULT: - { - set_handler_by_result_type(DECIMAL_RESULT); - decimals_to_set= MY_MIN(DECIMAL_MAX_SCALE, decimals_to_set); - int decimals_delta= args[0]->decimals - decimals_to_set; - int precision= args[0]->decimal_precision(); - int length_increase= ((decimals_delta <= 0) || truncate) ? 0:1; - - precision-= decimals_delta - length_increase; - decimals= MY_MIN(decimals_to_set, DECIMAL_MAX_SCALE); - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - break; - } - case ROW_RESULT: - case TIME_RESULT: - DBUG_ASSERT(0); /* This result type isn't handled */ + else + fix_length_and_dec_decimal(decimals_to_set); } - return FALSE; + else + fix_length_and_dec_double(args[0]->decimals); - } + double my_double_round(double value, longlong dec, bool dec_unsigned, bool truncate) { @@@ -5472,9 -5635,10 +5480,10 @@@ bool Item_func_get_user_var::fix_length { collation.set(&my_charset_bin, DERIVATION_IMPLICIT); null_value= 1; - set_handler_by_field_type(MYSQL_TYPE_LONG_BLOB); + set_handler(&type_handler_long_blob); max_length= MAX_BLOB_WIDTH; } + return false; } @@@ -6367,12 -6639,10 +6377,12 @@@ bool Item_func_sp::fix_length_and_dec( DBUG_ENTER("Item_func_sp::fix_length_and_dec"); DBUG_ASSERT(sp_result_field); - Type_std_attributes::set(sp_result_field); + Type_std_attributes::set(sp_result_field->type_std_attributes()); + // There is a bug in the line below. See MDEV-11292 for details. + collation.derivation= DERIVATION_COERCIBLE; maybe_null= 1; - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } @@@ -6678,308 -6981,10 +6688,309 @@@ my_decimal *Item_func_last_value::val_d } +bool Item_func_last_value::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) +{ + evaluate_sideeffects(); + bool tmp= last_value->get_date(ltime, fuzzydate); + null_value= last_value->null_value; + return tmp; +} + + - void Item_func_last_value::fix_length_and_dec() + bool Item_func_last_value::fix_length_and_dec() { last_value= args[arg_count -1]; Type_std_attributes::set(last_value); maybe_null= last_value->maybe_null; + return FALSE; } + + +void Cursor_ref::print_func(String *str, const char *func_name) +{ + append_identifier(current_thd, str, &m_cursor_name); + str->append(func_name); +} + + +sp_cursor *Cursor_ref::get_open_cursor_or_error() +{ + THD *thd= current_thd; + sp_cursor *c= thd->spcont->get_cursor(m_cursor_offset); + DBUG_ASSERT(c); + if (!c/*safety*/ || !c->is_open()) + { + my_message(ER_SP_CURSOR_NOT_OPEN, ER_THD(thd, ER_SP_CURSOR_NOT_OPEN), + MYF(0)); + return NULL; + } + return c; +} + + +longlong Item_func_cursor_isopen::val_int() +{ + sp_cursor *c= current_thd->spcont->get_cursor(m_cursor_offset); + DBUG_ASSERT(c != NULL); + return c ? c->is_open() : 0; +} + + +longlong Item_func_cursor_found::val_int() +{ + sp_cursor *c= get_open_cursor_or_error(); + return !(null_value= (!c || c->fetch_count() == 0)) && c->found(); +} + + +longlong Item_func_cursor_notfound::val_int() +{ + sp_cursor *c= get_open_cursor_or_error(); + return !(null_value= (!c || c->fetch_count() == 0)) && !c->found(); +} + + +longlong Item_func_cursor_rowcount::val_int() +{ + sp_cursor *c= get_open_cursor_or_error(); + return !(null_value= !c) ? c->row_count() : 0; +} + +/***************************************************************************** + SEQUENCE functions +*****************************************************************************/ + +longlong Item_func_nextval::val_int() +{ + longlong value; + int error; + const char *key; + uint length= get_table_def_key(table_list, &key); + THD *thd; + SEQUENCE_LAST_VALUE *entry; + char buff[80]; + String key_buff(buff,sizeof(buff), &my_charset_bin); + DBUG_ENTER("Item_func_nextval::val_int"); + update_table(); + DBUG_ASSERT(table && table->s->sequence); + thd= table->in_use; + + if (thd->count_cuted_fields == CHECK_FIELD_EXPRESSION) + { + /* Alter table checking if function works */ + null_value= 0; + DBUG_RETURN(0); + } + + if (table->s->tmp_table != NO_TMP_TABLE) + { + /* + Temporary tables has an extra \0 at end to distinguish it from + normal tables + */ + key_buff.copy(key, length, &my_charset_bin); + key_buff.append((char) 0); + key= key_buff.ptr(); + length++; + } + + if (!(entry= ((SEQUENCE_LAST_VALUE*) + my_hash_search(&thd->sequences, (uchar*) key, length)))) + { + if (!(key= (char*) my_memdup(key, length, MYF(MY_WME))) || + !(entry= new SEQUENCE_LAST_VALUE((uchar*) key, length))) + { + /* EOM, error given */ + my_free((char*) key); + delete entry; + null_value= 1; + DBUG_RETURN(0); + } + if (my_hash_insert(&thd->sequences, (uchar*) entry)) + { + /* EOM, error given */ + delete entry; + null_value= 1; + DBUG_RETURN(0); + } + } + entry->null_value= null_value= 0; + value= table->s->sequence->next_value(table, 0, &error); + entry->value= value; + entry->set_version(table); + + if (unlikely(error)) // Warning already printed + entry->null_value= null_value= 1; // For not strict mode + DBUG_RETURN(value); +} + + +/* Print for nextval and lastval */ + +void Item_func_nextval::print(String *str, enum_query_type query_type) +{ + char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME]; + LEX_CSTRING d_name= table_list->db; + LEX_CSTRING t_name= table_list->table_name; + bool use_db_name= d_name.str && d_name.str[0]; + THD *thd= current_thd; // Don't trust 'table' + + str->append(func_name()); + str->append('('); + + /* + for next_val we assume that table_list has been updated to contain + the current db. + */ + + if (lower_case_table_names > 0) + { + strmake(t_name_buff, t_name.str, MAX_ALIAS_NAME-1); + t_name.length= my_casedn_str(files_charset_info, t_name_buff); + t_name.str= t_name_buff; + if (use_db_name) + { + strmake(d_name_buff, d_name.str, MAX_ALIAS_NAME-1); + d_name.length= my_casedn_str(files_charset_info, d_name_buff); + d_name.str= d_name_buff; + } + } + + if (use_db_name) + { + append_identifier(thd, str, &d_name); + str->append('.'); + } + append_identifier(thd, str, &t_name); + str->append(')'); +} + + +/* Return last used value for sequence or NULL if sequence hasn't been used */ + +longlong Item_func_lastval::val_int() +{ + const char *key; + SEQUENCE_LAST_VALUE *entry; + uint length= get_table_def_key(table_list, &key); + THD *thd; + char buff[80]; + String key_buff(buff,sizeof(buff), &my_charset_bin); + DBUG_ENTER("Item_func_lastval::val_int"); + update_table(); + thd= table->in_use; + + if (table->s->tmp_table != NO_TMP_TABLE) + { + /* + Temporary tables has an extra \0 at end to distinguish it from + normal tables + */ + key_buff.copy(key, length, &my_charset_bin); + key_buff.append((char) 0); + key= key_buff.ptr(); + length++; + } + + if (!(entry= ((SEQUENCE_LAST_VALUE*) + my_hash_search(&thd->sequences, (uchar*) key, length)))) + { + /* Sequence not used */ + null_value= 1; + DBUG_RETURN(0); + } + if (entry->check_version(table)) + { + /* Table droped and re-created, remove current version */ + my_hash_delete(&thd->sequences, (uchar*) entry); + null_value= 1; + DBUG_RETURN(0); + } + + null_value= entry->null_value; + DBUG_RETURN(entry->value); +} + + +/* + Sets next value to be returned from sequences + + SELECT setval('foo', 42, 0); Next nextval will return 43 + SELECT setval('foo', 42, 0, true); Same as above + SELECT setval('foo', 42, 0, false); Next nextval will return 42 +*/ + +longlong Item_func_setval::val_int() +{ + longlong value; + int error; + THD *thd; + DBUG_ENTER("Item_func_setval::val_int"); + + update_table(); + DBUG_ASSERT(table && table->s->sequence); + thd= table->in_use; + + if (unlikely(thd->count_cuted_fields == CHECK_FIELD_EXPRESSION)) + { + /* Alter table checking if function works */ + null_value= 0; + DBUG_RETURN(0); + } + + value= nextval; + error= table->s->sequence->set_value(table, nextval, round, is_used); + if (unlikely(error)) + { + null_value= 1; + value= 0; + } + DBUG_RETURN(value); +} + + +/* Print for setval */ + +void Item_func_setval::print(String *str, enum_query_type query_type) +{ + char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME]; + LEX_CSTRING d_name= table_list->db; + LEX_CSTRING t_name= table_list->table_name; + bool use_db_name= d_name.str && d_name.str[0]; + THD *thd= current_thd; // Don't trust 'table' + + str->append(func_name()); + str->append('('); + + /* + for next_val we assume that table_list has been updated to contain + the current db. + */ + + if (lower_case_table_names > 0) + { + strmake(t_name_buff, t_name.str, MAX_ALIAS_NAME-1); + t_name.length= my_casedn_str(files_charset_info, t_name_buff); + t_name.str= t_name_buff; + if (use_db_name) + { + strmake(d_name_buff, d_name.str, MAX_ALIAS_NAME-1); + d_name.length= my_casedn_str(files_charset_info, d_name_buff); + d_name.str= d_name_buff; + } + } + + if (use_db_name) + { + append_identifier(thd, str, &d_name); + str->append('.'); + } + append_identifier(thd, str, &t_name); + str->append(','); + str->append_longlong(nextval); + str->append(','); + str->append_longlong(is_used); + str->append(','); + str->append_ulonglong(round); + str->append(')'); +} diff --cc sql/item_func.h index 049ef82f71e,0969cf2e3f0..b4f3cce612d --- a/sql/item_func.h +++ b/sql/item_func.h @@@ -394,11 -397,10 +394,15 @@@ public my_decimal *val_decimal(my_decimal *decimal_value); longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) rint(val_real()); } - enum Item_result result_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_real(ltime, fuzzydate); } + const Type_handler *type_handler() const { return &type_handler_double; } - void fix_length_and_dec() - { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } + bool fix_length_and_dec() - { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); return FALSE; } ++ { ++ decimals= NOT_FIXED_DEC; ++ max_length= float_length(decimals); ++ return FALSE; ++ } }; @@@ -781,86 -617,20 +785,86 @@@ public { collation.set_numeric(); } double val_real(); String *val_str(String*str); - enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } + const Type_handler *type_handler() const= 0; - void fix_length_and_dec() {} + bool fix_length_and_dec() { return FALSE; } }; -class Item_func_connection_id :public Item_int_func +class Item_long_func: public Item_int_func +{ +public: + Item_long_func(THD *thd): Item_int_func(thd) { } + Item_long_func(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_long_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_long_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} + Item_long_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { } + Item_long_func(THD *thd, Item_long_func *item) :Item_int_func(thd, item) {} + const Type_handler *type_handler() const { return &type_handler_long; } - void fix_length_and_dec() { max_length= 11; } ++ bool fix_length_and_dec() { max_length= 11; return FALSE; } +}; + + +class Item_longlong_func: public Item_int_func +{ +public: + Item_longlong_func(THD *thd): Item_int_func(thd) { } + Item_longlong_func(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_longlong_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_longlong_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} + Item_longlong_func(THD *thd, Item *a, Item *b, Item *c, Item *d): + Item_int_func(thd, a, b, c, d) {} + Item_longlong_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { } + Item_longlong_func(THD *thd, Item_longlong_func *item) :Item_int_func(thd, item) {} + const Type_handler *type_handler() const { return &type_handler_longlong; } +}; + + +class Cursor_ref +{ +protected: + LEX_CSTRING m_cursor_name; + uint m_cursor_offset; + class sp_cursor *get_open_cursor_or_error(); + Cursor_ref(const LEX_CSTRING *name, uint offset) + :m_cursor_name(*name), m_cursor_offset(offset) + { } + void print_func(String *str, const char *func_name); +}; + + + +class Item_func_cursor_rowcount: public Item_longlong_func, + public Cursor_ref +{ +public: + Item_func_cursor_rowcount(THD *thd, const LEX_CSTRING *name, uint offset) + :Item_longlong_func(thd), Cursor_ref(name, offset) { maybe_null= true; } + const char *func_name() const { return "%ROWCOUNT"; } + longlong val_int(); + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(func_name(), arg, VCOL_SESSION_FUNC); + } + void print(String *str, enum_query_type query_type) + { + return Cursor_ref::print_func(str, func_name()); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_cursor_rowcount>(thd, this); } +}; + + + +class Item_func_connection_id :public Item_long_func { longlong value; public: - Item_func_connection_id(THD *thd): Item_int_func(thd) {} + Item_func_connection_id(THD *thd): Item_long_func(thd) { unsigned_flag=1; } const char *func_name() const { return "connection_id"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); bool fix_fields(THD *thd, Item **ref); longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } bool check_vcol_func_processor(void *arg) @@@ -903,23 -667,7 +907,23 @@@ public */ set_if_bigger(char_length, 1U + (unsigned_flag ? 0 : 1)); fix_char_length(char_length); - return FALSE; + } + void fix_length_and_dec_string() + { + /* + For strings, use decimal_int_part() instead of max_char_length(). + This is important for Item_hex_hybrid: + SELECT CAST(0x1FFFFFFFF AS SIGNED); + Length is 5, decimal_int_part() is 13. + */ + uint32 char_length= MY_MIN(args[0]->decimal_int_part(), + MY_INT64_NUM_DECIMAL_DIGITS); + set_if_bigger(char_length, 1U + (unsigned_flag ? 0 : 1)); + fix_char_length(char_length); + } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_func_signed_fix_length_and_dec(this); ++ return args[0]->type_handler()->Item_func_signed_fix_length_and_dec(this); } virtual void print(String *str, enum_query_type query_type); uint decimal_precision() const { return args[0]->decimal_precision(); } @@@ -949,14 -691,9 +953,14 @@@ public null_value= args[0]->null_value; return value; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_func_unsigned_fix_length_and_dec(this); ++ return args[0]->type_handler()->Item_func_unsigned_fix_length_and_dec(this); + } + uint decimal_precision() const { return max_length; } virtual void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_unsigned>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_unsigned>(thd, this); } }; @@@ -976,14 -712,9 +980,15 @@@ public double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal*); - enum Item_result result_type () const { return DECIMAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } - bool fix_length_and_dec() { return FALSE; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_decimal(ltime, fuzzydate); } + const Type_handler *type_handler() const { return &type_handler_newdecimal; } + void fix_length_and_dec_generic() {} - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_decimal_typecast_fix_length_and_dec(this); ++ return ++ args[0]->type_handler()->Item_decimal_typecast_fix_length_and_dec(this); + } const char *func_name() const { return "decimal_typecast"; } virtual void print(String *str, enum_query_type query_type); bool need_parentheses_in_default() { return true; } @@@ -1002,11 -733,8 +1007,12 @@@ public max_length= (uint32) len; } double val_real(); - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } - bool fix_length_and_dec() { maybe_null= 1; return FALSE; } + void fix_length_and_dec_generic() { maybe_null= 1; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_double_typecast_fix_length_and_dec(this); ++ return ++ args[0]->type_handler()->Item_double_typecast_fix_length_and_dec(this); + } const char *func_name() const { return "double_typecast"; } virtual void print(String *str, enum_query_type query_type); bool need_parentheses_in_default() { return true; } @@@ -1032,7 -761,6 +1038,7 @@@ public Item_func_additive_op(thd, a, b) {} const char *func_name() const { return "+"; } enum precedence precedence() const { return ADD_PRECEDENCE; } - void fix_length_and_dec(); ++ bool fix_length_and_dec(); longlong int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); @@@ -1050,25 -778,9 +1056,25 @@@ public longlong int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_minus>(thd, mem_root, this); } + void fix_unsigned_flag(); + void fix_length_and_dec_double() + { + Item_func_additive_op::fix_length_and_dec_double(); + fix_unsigned_flag(); + } + void fix_length_and_dec_decimal() + { + Item_func_additive_op::fix_length_and_dec_decimal(); + fix_unsigned_flag(); + } + void fix_length_and_dec_int() + { + Item_func_additive_op::fix_length_and_dec_int(); + fix_unsigned_flag(); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_minus>(thd, this); } }; @@@ -1083,11 -795,10 +1089,11 @@@ public double real_op(); my_decimal *decimal_op(my_decimal *); void result_precision(); - void fix_length_and_dec(); ++ bool fix_length_and_dec(); bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;} - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_mul>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_mul>(thd, this); } }; @@@ -1101,12 -812,10 +1107,12 @@@ public my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "/"; } enum precedence precedence() const { return MUL_PRECEDENCE; } - void fix_length_and_dec(); + bool fix_length_and_dec(); + void fix_length_and_dec_double(); + void fix_length_and_dec_int(); void result_precision(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_div>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_div>(thd, this); } }; @@@ -1118,9 -827,7 +1124,9 @@@ public longlong val_int(); const char *func_name() const { return "DIV"; } enum precedence precedence() const { return MUL_PRECEDENCE; } + const Type_handler *type_handler() const + { return type_handler_long_or_longlong(); } - void fix_length_and_dec(); + bool fix_length_and_dec(); void print(String *str, enum_query_type query_type) { print_op(str, query_type); @@@ -1141,31 -848,14 +1147,31 @@@ public longlong int_op(); double real_op(); my_decimal *decimal_op(my_decimal *); - const char *func_name() const { return "%"; } + const char *func_name() const { return "MOD"; } enum precedence precedence() const { return MUL_PRECEDENCE; } void result_precision(); - void fix_length_and_dec(); + bool fix_length_and_dec(); + void fix_length_and_dec_double() + { + Item_num_op::fix_length_and_dec_double(); + unsigned_flag= args[0]->unsigned_flag; + } + void fix_length_and_dec_decimal() + { + Item_num_op::fix_length_and_dec_decimal(); + unsigned_flag= args[0]->unsigned_flag; + } + void fix_length_and_dec_int() + { + max_length= MY_MAX(args[0]->max_length, args[1]->max_length); + decimals= 0; + unsigned_flag= args[0]->unsigned_flag; + set_handler(type_handler_long_or_longlong()); + } bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;} - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_mod>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_mod>(thd, this); } }; @@@ -1184,14 -874,13 +1190,14 @@@ public str->append(func_name()); args[0]->print_parenthesised(str, query_type, precedence()); } + void fix_length_and_dec_int(); + void fix_length_and_dec_double(); + void fix_length_and_dec_decimal(); - void fix_length_and_dec(); + bool fix_length_and_dec(); uint decimal_precision() const { return args[0]->decimal_precision(); } - bool check_partition_func_processor(void *int_arg) {return FALSE;} - bool check_vcol_func_processor(void *arg) { return FALSE;} bool need_parentheses_in_default() { return true; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_neg>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_neg>(thd, this); } }; @@@ -1203,12 -892,11 +1209,12 @@@ public longlong int_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "abs"; } + void fix_length_and_dec_int(); + void fix_length_and_dec_double(); + void fix_length_and_dec_decimal(); - void fix_length_and_dec(); + bool fix_length_and_dec(); - bool check_partition_func_processor(void *int_arg) {return FALSE;} - bool check_vcol_func_processor(void *arg) { return FALSE;} - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_abs>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_abs>(thd, this); } }; // A class to handle logarithmic and trigonometric functions @@@ -1381,9 -1068,7 +1388,9 @@@ class Item_func_int_val :public Item_fu { public: Item_func_int_val(THD *thd, Item *a): Item_func_num1(thd, a) {} + void fix_length_and_dec_double(); + void fix_length_and_dec_int_or_decimal(); - void fix_length_and_dec(); + bool fix_length_and_dec(); }; @@@ -1426,15 -1113,9 +1433,15 @@@ public double real_op(); longlong int_op(); my_decimal *decimal_op(my_decimal *); - bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_round>(thd, mem_root, this); } + void fix_arg_decimal(); + void fix_arg_int(); + void fix_arg_double(); - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_func_round_fix_length_and_dec(this); ++ return args[0]->type_handler()->Item_func_round_fix_length_and_dec(this); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_round>(thd, this); } }; @@@ -1465,18 -1144,14 +1472,18 @@@ private }; -class Item_func_sign :public Item_int_func +class Item_func_sign :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_can_return_real(func_name()); } public: - Item_func_sign(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_sign(THD *thd, Item *a): Item_long_func(thd, a) {} const char *func_name() const { return "sign"; } + uint decimal_precision() const { return 1; } - void fix_length_and_dec() { fix_char_length(2); } ++ bool fix_length_and_dec() { fix_char_length(2); return FALSE; } longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_sign>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_sign>(thd, this); } }; @@@ -1492,10 -1165,10 +1499,14 @@@ public Item_real_func(thd, a), name(name_arg), mul(mul_arg), add(add_arg) {} double val_real(); const char *func_name() const { return name; } - void fix_length_and_dec() - { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } + bool fix_length_and_dec() - { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_units>(thd, mem_root, this); } ++ { ++ decimals= NOT_FIXED_DEC; ++ max_length= float_length(decimals); ++ return FALSE; ++ } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_units>(thd, this); } }; @@@ -1520,69 -1191,12 +1531,70 @@@ public Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg): Item_hybrid_func(thd, list), cmp_sign(cmp_sign_arg) {} - double val_real(); - longlong val_int(); - String *val_str(String *); - my_decimal *val_decimal(my_decimal *); - bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); - bool fix_length_and_dec(); + String *val_str_native(String *str); + double val_real_native(); + longlong val_int_native(); + my_decimal *val_decimal_native(my_decimal *); + bool get_date_native(MYSQL_TIME *res, ulonglong fuzzydate); + bool get_time_native(MYSQL_TIME *res); + + double val_real() + { + DBUG_ASSERT(fixed); + return Item_func_min_max::type_handler()-> + Item_func_min_max_val_real(this); + } + longlong val_int() + { + DBUG_ASSERT(fixed); + return Item_func_min_max::type_handler()-> + Item_func_min_max_val_int(this); + } + String *val_str(String *str) + { + DBUG_ASSERT(fixed); + return Item_func_min_max::type_handler()-> + Item_func_min_max_val_str(this, str); + } + my_decimal *val_decimal(my_decimal *dec) + { + DBUG_ASSERT(fixed); + return Item_func_min_max::type_handler()-> + Item_func_min_max_val_decimal(this, dec); + } + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) + { + DBUG_ASSERT(fixed); + return Item_func_min_max::type_handler()-> + Item_func_min_max_get_date(this, res, fuzzy_date); + } + void aggregate_attributes_real(Item **items, uint nitems) + { + /* + Aggregating attributes for the double data type for LEAST/GREATEST + is almost the same with aggregating for CASE-alike hybrid functions, + (CASE..THEN, COALESCE, IF, etc). + There is one notable difference though, when a numeric argument is mixed + with a string argument: + - CASE-alike functions return a string data type in such cases + COALESCE(10,'x') -> VARCHAR(2) = '10' + - LEAST/GREATEST returns double: + GREATEST(10,'10e4') -> DOUBLE = 100000 + As the string argument can represent a number in the scientific notation, + like in the example above, max_length of the result can be longer than + max_length of the arguments. To handle this properly, max_length is + additionally assigned to the result of float_length(decimals). + */ + Item_func::aggregate_attributes_real(items, nitems); + max_length= float_length(decimals); + } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + if (aggregate_for_min_max(func_name(), args, arg_count)) - return; ++ return true; + fix_attributes(args, arg_count); ++ return false; + } }; class Item_func_min :public Item_func_min_max @@@ -1615,35 -1229,27 +1627,36 @@@ public Item_func_rollup_const(THD *thd, Item *a): Item_func(thd, a) { name= a->name; - name_length= a->name_length; } - double val_real() { return args[0]->val_real(); } - longlong val_int() { return args[0]->val_int(); } - String *val_str(String *str) { return args[0]->val_str(str); } - my_decimal *val_decimal(my_decimal *dec) { return args[0]->val_decimal(dec); } + double val_real() { return val_real_from_item(args[0]); } + longlong val_int() { return val_int_from_item(args[0]); } + String *val_str(String *str) { return val_str_from_item(args[0], str); } + my_decimal *val_decimal(my_decimal *dec) + { return val_decimal_from_item(args[0], dec); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_item(args[0], ltime, fuzzydate); } const char *func_name() const { return "rollup_const"; } bool const_item() const { return 0; } - Item_result result_type() const { return args[0]->result_type(); } - enum_field_types field_type() const { return args[0]->field_type(); } + const Type_handler *type_handler() const { return args[0]->type_handler(); } - void fix_length_and_dec() + bool fix_length_and_dec() { collation= args[0]->collation; max_length= args[0]->max_length; - decimals=args[0]->decimals; - /* The item could be a NULL constant. */ - null_value= args[0]->is_null(); + decimals=args[0]->decimals; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_rollup_const>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_rollup_const>(thd, this); } +}; + + +class Item_long_func_length: public Item_long_func +{ + bool check_arguments() const + { return args[0]->check_type_can_return_str(func_name()); } +public: + Item_long_func_length(THD *thd, Item *a): Item_long_func(thd, a) {} - void fix_length_and_dec() { max_length=10; } ++ bool fix_length_and_dec() { max_length=10; return FALSE; } }; @@@ -1651,48 -1257,44 +1664,49 @@@ class Item_func_octet_length :public It { String value; public: - Item_func_length(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_octet_length(THD *thd, Item *a): Item_long_func_length(thd, a) {} longlong val_int(); - const char *func_name() const { return "length"; } - bool fix_length_and_dec() { max_length=10; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_length>(thd, mem_root, this); } + const char *func_name() const { return "octet_length"; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_octet_length>(thd, this); } }; -class Item_func_bit_length :public Item_func_length +class Item_func_bit_length :public Item_longlong_func { + String value; public: - Item_func_bit_length(THD *thd, Item *a): Item_func_length(thd, a) {} - longlong val_int() - { DBUG_ASSERT(fixed == 1); return Item_func_length::val_int()*8; } + Item_func_bit_length(THD *thd, Item *a): Item_longlong_func(thd, a) {} - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + max_length= 11; // 0x100000000*8 = 34,359,738,368 ++ return FALSE; + } + longlong val_int(); const char *func_name() const { return "bit_length"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_bit_length>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_bit_length>(thd, this); } }; -class Item_func_char_length :public Item_int_func +class Item_func_char_length :public Item_long_func_length { String value; public: - Item_func_char_length(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_char_length(THD *thd, Item *a): Item_long_func_length(thd, a) {} longlong val_int(); const char *func_name() const { return "char_length"; } - bool fix_length_and_dec() { max_length=10; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_char_length>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_char_length>(thd, this); } }; -class Item_func_coercibility :public Item_int_func +class Item_func_coercibility :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_can_return_str(func_name()); } public: - Item_func_coercibility(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_coercibility(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "coercibility"; } - void fix_length_and_dec() { max_length=10; maybe_null= 0; } + bool fix_length_and_dec() { max_length=10; maybe_null= 0; return FALSE; } bool eval_not_null_tables(void *) { not_null_tables_cache= 0; @@@ -1722,20 -1312,14 +1736,20 @@@ class Item_func_locate :public Item_lon String value1,value2; DTCollation cmp_collation; public: - Item_func_locate(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} - Item_func_locate(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} + Item_func_locate(THD *thd, Item *a, Item *b) + :Item_long_func(thd, a, b) {} + Item_func_locate(THD *thd, Item *a, Item *b, Item *c) + :Item_long_func(thd, a, b, c) {} const char *func_name() const { return "locate"; } longlong val_int(); - void fix_length_and_dec() - bool fix_length_and_dec(); ++ bool fix_length_and_dec() + { + max_length= MY_INT32_NUM_DECIMAL_DIGITS; - agg_arg_charsets_for_comparison(cmp_collation, args, 2); ++ return agg_arg_charsets_for_comparison(cmp_collation, args, 2); + } virtual void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_locate>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_locate>(thd, this); } }; @@@ -1745,71 -1329,62 +1759,71 @@@ class Item_func_field :public Item_long Item_result cmp_type; DTCollation cmp_collation; public: - Item_func_field(THD *thd, List<Item> &list): Item_int_func(thd, list) {} + Item_func_field(THD *thd, List<Item> &list): Item_long_func(thd, list) {} longlong val_int(); const char *func_name() const { return "field"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_field>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_field>(thd, this); } }; -class Item_func_ascii :public Item_int_func +class Item_func_ascii :public Item_long_func { + bool check_arguments() const + { return check_argument_types_can_return_str(0, arg_count); } String value; public: - Item_func_ascii(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_ascii(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "ascii"; } - void fix_length_and_dec() { max_length=3; } + bool fix_length_and_dec() { max_length=3; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_ascii>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_ascii>(thd, this); } }; -class Item_func_ord :public Item_int_func +class Item_func_ord :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_can_return_str(func_name()); } String value; public: - Item_func_ord(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_ord(THD *thd, Item *a): Item_long_func(thd, a) {} - void fix_length_and_dec() { fix_char_length(7); } ++ bool fix_length_and_dec() { fix_char_length(7); return FALSE; } longlong val_int(); const char *func_name() const { return "ord"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_ord>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_ord>(thd, this); } }; -class Item_func_find_in_set :public Item_int_func +class Item_func_find_in_set :public Item_long_func { + bool check_arguments() const + { return check_argument_types_can_return_str(0, 2); } String value,value2; uint enum_value; ulonglong enum_bit; DTCollation cmp_collation; public: Item_func_find_in_set(THD *thd, Item *a, Item *b): - Item_int_func(thd, a, b), enum_value(0) {} + Item_long_func(thd, a, b), enum_value(0) {} longlong val_int(); const char *func_name() const { return "find_in_set"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_find_in_set>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_find_in_set>(thd, this); } }; /* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */ -class Item_func_bit: public Item_int_func +class Item_func_bit: public Item_longlong_func { + bool check_arguments() const + { return check_argument_types_can_return_int(0, arg_count); } public: - Item_func_bit(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} - Item_func_bit(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_bit(THD *thd, Item *a, Item *b): Item_longlong_func(thd, a, b) {} + Item_func_bit(THD *thd, Item *a): Item_longlong_func(thd, a) {} - void fix_length_and_dec() { unsigned_flag= 1; } + bool fix_length_and_dec() { unsigned_flag= 1; return FALSE; } virtual inline void print(String *str, enum_query_type query_type) { @@@ -1836,21 -1411,19 +1850,21 @@@ public longlong val_int(); const char *func_name() const { return "&"; } enum precedence precedence() const { return BITAND_PRECEDENCE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_bit_and>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_bit_and>(thd, this); } }; -class Item_func_bit_count :public Item_int_func +class Item_func_bit_count :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_can_return_int(func_name()); } public: - Item_func_bit_count(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_bit_count(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "bit_count"; } - void fix_length_and_dec() { max_length=2; } + bool fix_length_and_dec() { max_length=2; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_bit_count>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_bit_count>(thd, this); } }; class Item_func_shift_left :public Item_func_bit @@@ -1892,20 -1465,20 +1906,21 @@@ public }; -class Item_func_last_insert_id :public Item_int_func +class Item_func_last_insert_id :public Item_longlong_func { + bool check_arguments() const + { return check_argument_types_can_return_int(0, arg_count); } public: - Item_func_last_insert_id(THD *thd): Item_int_func(thd) {} - Item_func_last_insert_id(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_last_insert_id(THD *thd): Item_longlong_func(thd) {} + Item_func_last_insert_id(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int(); const char *func_name() const { return "last_insert_id"; } - void fix_length_and_dec() + bool fix_length_and_dec() { - unsigned_flag= TRUE; + unsigned_flag= true; if (arg_count) max_length= args[0]->max_length; - unsigned_flag=1; + return FALSE; } bool fix_fields(THD *thd, Item **ref); bool check_vcol_func_processor(void *arg) @@@ -1944,13 -1512,10 +1959,13 @@@ public void item_func_sleep_init(void); void item_func_sleep_free(void); -class Item_func_sleep :public Item_int_func +class Item_func_sleep :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_can_return_real(func_name()); } public: - Item_func_sleep(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_sleep(THD *thd, Item *a): Item_long_func(thd, a) {} - void fix_length_and_dec() { fix_char_length(1); } ++ bool fix_length_and_dec() { fix_char_length(1); return FALSE; } bool const_item() const { return 0; } const char *func_name() const { return "sleep"; } table_map used_tables() const @@@ -2093,10 -1655,10 +2108,10 @@@ class Item_func_udf_float :public Item_ } double val_real(); String *val_str(String *str); - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + const Type_handler *type_handler() const { return &type_handler_double; } - void fix_length_and_dec() { fix_num_length_and_dec(); } + bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_udf_float>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_udf_float>(thd, this); } }; @@@ -2111,10 -1673,11 +2126,10 @@@ public longlong val_int(); double val_real() { return (double) Item_func_udf_int::val_int(); } String *val_str(String *str); - enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + const Type_handler *type_handler() const { return &type_handler_longlong; } - void fix_length_and_dec() { decimals= 0; max_length= 21; } + bool fix_length_and_dec() { decimals= 0; max_length= 21; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_udf_int>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_udf_int>(thd, this); } }; @@@ -2129,10 -1692,11 +2144,10 @@@ public double val_real(); my_decimal *val_decimal(my_decimal *); String *val_str(String *str); - enum Item_result result_type () const { return DECIMAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + const Type_handler *type_handler() const { return &type_handler_newdecimal; } - void fix_length_and_dec() { fix_num_length_and_dec(); } + bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_udf_decimal>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_udf_decimal>(thd, this); } }; @@@ -2168,10 -1732,11 +2183,10 @@@ public string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); return dec_buf; } - enum Item_result result_type () const { return STRING_RESULT; } - enum_field_types field_type() const { return string_field_type(); } + const Type_handler *type_handler() const { return string_type_handler(); } - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_udf_str>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_udf_str>(thd, this); } }; #else /* Dummy functions to get sql_yacc.cc compiled */ @@@ -2222,7 -1785,8 +2237,7 @@@ public { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed == 1); null_value= 1; return 0.0; } longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } - void fix_length_and_dec() { maybe_null=1; max_length=0; } - enum Item_result result_type () const { return STRING_RESULT; } + bool fix_length_and_dec() { maybe_null=1; max_length=0; return FALSE; } }; #endif /* HAVE_DLOPEN */ @@@ -2230,19 -1794,14 +2245,19 @@@ void mysql_ull_cleanup(THD *thd); void mysql_ull_set_explicit_lock_duration(THD *thd); -class Item_func_get_lock :public Item_int_func +class Item_func_get_lock :public Item_long_func { + bool check_arguments() const + { + return args[0]->check_type_general_purpose_string(func_name()) || + args[1]->check_type_can_return_real(func_name()); + } String value; public: - Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_int_func(thd, a, b) {} + Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "get_lock"; } - void fix_length_and_dec() { max_length=1; maybe_null=1;} + bool fix_length_and_dec() { max_length=1; maybe_null=1; return FALSE; } table_map used_tables() const { return used_tables_cache | RAND_TABLE_BIT; @@@ -2253,20 -1812,18 +2268,20 @@@ { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_get_lock>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_get_lock>(thd, this); } }; -class Item_func_release_lock :public Item_int_func +class Item_func_release_lock :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_general_purpose_string(func_name()); } String value; public: - Item_func_release_lock(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_release_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "release_lock"; } - void fix_length_and_dec() { max_length= 1; maybe_null= 1;} + bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; } table_map used_tables() const { return used_tables_cache | RAND_TABLE_BIT; @@@ -2283,27 -1840,18 +2298,27 @@@ /* replication functions */ -class Item_master_pos_wait :public Item_int_func +class Item_master_pos_wait :public Item_longlong_func { + bool check_arguments() const + { + return + args[0]->check_type_general_purpose_string(func_name()) || + args[1]->check_type_can_return_int(func_name()) || + (arg_count > 2 && args[2]->check_type_can_return_int(func_name())) || + (arg_count > 3 && args[3]->check_type_general_purpose_string(func_name())); + } String value; public: - Item_master_pos_wait(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_master_pos_wait(THD *thd, Item *a, Item *b) + :Item_longlong_func(thd, a, b) {} Item_master_pos_wait(THD *thd, Item *a, Item *b, Item *c): - Item_int_func(thd, a, b, c) {} + Item_longlong_func(thd, a, b, c) {} Item_master_pos_wait(THD *thd, Item *a, Item *b, Item *c, Item *d): - Item_int_func(thd, a, b, c, d) {} + Item_longlong_func(thd, a, b, c, d) {} longlong val_int(); const char *func_name() const { return "master_pos_wait"; } - void fix_length_and_dec() { max_length=21; maybe_null=1;} + bool fix_length_and_dec() { max_length=21; maybe_null=1; return FALSE; } bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); @@@ -2313,22 -1861,15 +2328,22 @@@ }; -class Item_master_gtid_wait :public Item_int_func +class Item_master_gtid_wait :public Item_long_func { + bool check_arguments() const + { + return args[0]->check_type_general_purpose_string(func_name()) || + (arg_count > 1 && args[1]->check_type_can_return_real(func_name())); + } String value; public: - Item_master_gtid_wait(THD *thd, Item *a): Item_int_func(thd, a) {} - Item_master_gtid_wait(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_master_gtid_wait(THD *thd, Item *a) + :Item_long_func(thd, a) {} + Item_master_gtid_wait(THD *thd, Item *a, Item *b) + :Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "master_gtid_wait"; } - void fix_length_and_dec() { max_length=2; } + bool fix_length_and_dec() { max_length=2; return FALSE; } bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); @@@ -2425,7 -1960,13 +2440,7 @@@ public void save_item_result(Item *item); bool update(); bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); - Field *create_field_for_create_select(TABLE *table) - { - return result_type() != STRING_RESULT ? - create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS) : - tmp_table_field_from_field_type(table, false, true); - } void print(String *str, enum_query_type query_type); enum precedence precedence() const { return ASSIGN_PRECEDENCE; } void print_as_stmt(String *str, enum_query_type query_type); @@@ -2708,38 -2211,42 +2723,46 @@@ public longlong val_int(); const char *func_name() const { return "^"; } enum precedence precedence() const { return BITXOR_PRECEDENCE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_bit_xor>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_bit_xor>(thd, this); } }; -class Item_func_is_free_lock :public Item_int_func +class Item_func_is_free_lock :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_general_purpose_string(func_name()); } String value; public: - Item_func_is_free_lock(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_is_free_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "is_free_lock"; } - void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} + bool fix_length_and_dec() + { + decimals=0; max_length=1; maybe_null=1; + return FALSE; + } bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_is_free_lock>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_is_free_lock>(thd, this); } }; -class Item_func_is_used_lock :public Item_int_func +class Item_func_is_used_lock :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_general_purpose_string(func_name()); } String value; public: - Item_func_is_used_lock(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_is_used_lock(THD *thd, Item *a): Item_long_func(thd, a) {} longlong val_int(); const char *func_name() const { return "is_used_lock"; } - void fix_length_and_dec() { decimals=0; max_length=10; maybe_null=1;} + bool fix_length_and_dec() + { + decimals=0; max_length=10; maybe_null=1; + return FALSE; + } bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); @@@ -2782,13 -2291,14 +2805,13 @@@ public }; -class Item_func_row_count :public Item_int_func +class Item_func_row_count :public Item_longlong_func { public: - Item_func_row_count(THD *thd): Item_int_func(thd) {} + Item_func_row_count(THD *thd): Item_longlong_func(thd) {} longlong val_int(); const char *func_name() const { return "row_count"; } - void fix_length_and_dec() { decimals= 0; maybe_null=0; } + bool fix_length_and_dec() { decimals= 0; maybe_null=0; return FALSE; } bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); @@@ -2940,62 -2456,19 +2963,63 @@@ public }; -class Item_func_found_rows :public Item_int_func +class Item_func_found_rows :public Item_longlong_func { public: - Item_func_found_rows(THD *thd): Item_int_func(thd) {} + Item_func_found_rows(THD *thd): Item_longlong_func(thd) {} longlong val_int(); const char *func_name() const { return "found_rows"; } - void fix_length_and_dec() { decimals= 0; maybe_null=0; } + bool fix_length_and_dec() { decimals= 0; maybe_null=0; return FALSE; } bool check_vcol_func_processor(void *arg) { return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_found_rows>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_found_rows>(thd, this); } +}; + + +class Item_func_oracle_sql_rowcount :public Item_longlong_func +{ +public: + Item_func_oracle_sql_rowcount(THD *thd): Item_longlong_func(thd) {} + longlong val_int(); + const char *func_name() const { return "SQL%ROWCOUNT"; } + void print(String *str, enum_query_type query_type) + { + str->append(func_name()); + } + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_oracle_sql_rowcount>(thd, this); } +}; + + +class Item_func_sqlcode: public Item_long_func +{ +public: + Item_func_sqlcode(THD *thd): Item_long_func(thd) { } + longlong val_int(); + const char *func_name() const { return "SQLCODE"; } + void print(String *str, enum_query_type query_type) + { + str->append(func_name()); + } + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE); + } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + maybe_null= null_value= false; + max_length= 11; ++ return FALSE; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_sqlcode>(thd, this); } }; @@@ -3030,10 -2503,9 +3054,10 @@@ public longlong val_int(); String *val_str(String *); my_decimal *val_decimal(my_decimal *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - void fix_length_and_dec(); + bool fix_length_and_dec(); - enum Item_result result_type () const { return last_value->result_type(); } const char *func_name() const { return "last_value"; } + const Type_handler *type_handler() const { return last_value->type_handler(); } bool eval_not_null_tables(void *) { not_null_tables_cache= 0; @@@ -3046,90 -2519,8 +3070,91 @@@ Item_func::update_used_tables(); maybe_null= last_value->maybe_null; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_last_value>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_last_value>(thd, this); } +}; + + +/* Implementation for sequences: NEXT VALUE FOR sequence and NEXTVAL() */ + +class Item_func_nextval :public Item_longlong_func +{ +protected: + TABLE_LIST *table_list; + TABLE *table; +public: + Item_func_nextval(THD *thd, TABLE_LIST *table_list_arg): + Item_longlong_func(thd), table_list(table_list_arg) {} + longlong val_int(); + const char *func_name() const { return "nextval"; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + unsigned_flag= 0; + max_length= MAX_BIGINT_WIDTH; + maybe_null= 1; /* In case of errors */ ++ return FALSE; + } + /* + update_table() function must be called during the value function + as in case of DEFAULT the sequence table may not yet be open + while fix_fields() are called + */ + void update_table() + { + if (!(table= table_list->table)) + { + /* + If nextval was used in DEFAULT then next_local points to + the table_list used by to open the sequence table + */ + table= table_list->next_local->table; + } + } + bool const_item() const { return 0; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_nextval>(thd, this); } + void print(String *str, enum_query_type query_type); + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(func_name(), "()", arg, + (VCOL_NON_DETERMINISTIC | + VCOL_NOT_VIRTUAL)); + } +}; + + +/* Implementation for sequences: LASTVAL(sequence), PostgreSQL style */ + +class Item_func_lastval :public Item_func_nextval +{ +public: + Item_func_lastval(THD *thd, TABLE_LIST *table_list_arg): + Item_func_nextval(thd, table_list_arg) {} + longlong val_int(); + const char *func_name() const { return "lastval"; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_lastval>(thd, this); } +}; + + +/* Implementation for sequences: SETVAL(sequence), PostgreSQL style */ + +class Item_func_setval :public Item_func_nextval +{ + longlong nextval; + ulonglong round; + bool is_used; +public: + Item_func_setval(THD *thd, TABLE_LIST *table_list_arg, longlong nextval_arg, + ulonglong round_arg, bool is_used_arg) + : Item_func_nextval(thd, table_list_arg), + nextval(nextval_arg), round(round_arg), is_used(is_used_arg) + {} + longlong val_int(); + const char *func_name() const { return "setval"; } + void print(String *str, enum_query_type query_type); + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_setval>(thd, this); } }; diff --cc sql/item_geofunc.cc index aee44a7a01f,246be438e36..4c2a2fa8b11 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@@ -40,12 -40,22 +40,13 @@@ #include "opt_range.h" - void Item_geometry_func::fix_length_and_dec() -Field *Item_geometry_func::create_field_for_create_select(TABLE *t_arg) -{ - Field *result; - if ((result= new Field_geom(max_length, maybe_null, name, t_arg->s, - get_geometry_type()))) - result->init(t_arg); - return result; -} - + bool Item_geometry_func::fix_length_and_dec() { collation.set(&my_charset_bin); decimals=0; - max_length= (uint32) 4294967295U; + max_length= (uint32) UINT_MAX32; maybe_null= 1; + return FALSE; } @@@ -214,11 -224,12 +215,12 @@@ String *Item_func_as_wkt::val_str_ascii } - void Item_func_as_wkt::fix_length_and_dec() + bool Item_func_as_wkt::fix_length_and_dec() { collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); - max_length=MAX_BLOB_WIDTH; + max_length= (uint32) UINT_MAX32; maybe_null= 1; + return FALSE; } diff --cc sql/item_geofunc.h index 8101433abb5,acc94183d47..0e727829ce7 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@@ -38,164 -38,13 +38,164 @@@ public Item_geometry_func(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {} Item_geometry_func(THD *thd, List<Item> &list): Item_str_func(thd, list) {} - void fix_length_and_dec(); + bool fix_length_and_dec(); - enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; } - Field *create_field_for_create_select(TABLE *table); + const Type_handler *type_handler() const { return &type_handler_geometry; } }; + +/* + Functions returning REAL measurements of a single GEOMETRY argument +*/ +class Item_real_func_args_geometry: public Item_real_func +{ +protected: + String value; + bool check_arguments() const + { + DBUG_ASSERT(arg_count == 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_real_func_args_geometry(THD *thd, Item *a) + :Item_real_func(thd, a) {} +}; + + +/* + Functions returning INT measurements of a single GEOMETRY argument +*/ +class Item_long_func_args_geometry: public Item_long_func +{ + bool check_arguments() const + { + DBUG_ASSERT(arg_count == 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +protected: + String value; +public: + Item_long_func_args_geometry(THD *thd, Item *a) + :Item_long_func(thd, a) {} +}; + + +/* + Functions returning BOOL measurements of a single GEOMETRY argument +*/ +class Item_bool_func_args_geometry: public Item_bool_func +{ +protected: + String value; + bool check_arguments() const + { + DBUG_ASSERT(arg_count == 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_bool_func_args_geometry(THD *thd, Item *a) + :Item_bool_func(thd, a) {} +}; + + +/* + Functions returning ASCII string measurements of a single GEOMETRY argument +*/ +class Item_str_ascii_func_args_geometry: public Item_str_ascii_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_str_ascii_func_args_geometry(THD *thd, Item *a) + :Item_str_ascii_func(thd, a) {} + Item_str_ascii_func_args_geometry(THD *thd, Item *a, Item *b) + :Item_str_ascii_func(thd, a, b) {} + Item_str_ascii_func_args_geometry(THD *thd, Item *a, Item *b, Item *c) + :Item_str_ascii_func(thd, a, b, c) {} +}; + + +/* + Functions returning binary string measurements of a single GEOMETRY argument +*/ +class Item_binary_func_args_geometry: public Item_str_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_binary_func_args_geometry(THD *thd, Item *a) + :Item_str_func(thd, a) {} +}; + + +/* + Functions returning GEOMETRY measurements of a single GEOEMETRY argument +*/ +class Item_geometry_func_args_geometry: public Item_geometry_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 1); + return args[0]->check_type_or_binary(func_name(), &type_handler_geometry); + } +public: + Item_geometry_func_args_geometry(THD *thd, Item *a) + :Item_geometry_func(thd, a) {} + Item_geometry_func_args_geometry(THD *thd, Item *a, Item *b) + :Item_geometry_func(thd, a, b) {} +}; + + +/* + Functions returning REAL result relationships between two GEOMETRY arguments +*/ +class Item_real_func_args_geometry_geometry: public Item_real_func +{ +protected: + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 2); + return check_argument_types_or_binary(&type_handler_geometry, 0, 2); + } +public: + Item_real_func_args_geometry_geometry(THD *thd, Item *a, Item *b) + :Item_real_func(thd, a, b) {} +}; + + +/* + Functions returning BOOL result relationships between two GEOMETRY arguments +*/ +class Item_bool_func_args_geometry_geometry: public Item_bool_func +{ +protected: + String value; + bool check_arguments() const + { + DBUG_ASSERT(arg_count >= 2); + return check_argument_types_or_binary(&type_handler_geometry, 0, 2); + } +public: + Item_bool_func_args_geometry_geometry(THD *thd, Item *a, Item *b, Item *c) + :Item_bool_func(thd, a, b, c) {} +}; + + class Item_func_geometry_from_text: public Item_geometry_func { + bool check_arguments() const + { + return args[0]->check_type_general_purpose_string(func_name()) || + check_argument_types_can_return_int(1, MY_MIN(2, arg_count)); + } public: Item_func_geometry_from_text(THD *thd, Item *a): Item_geometry_func(thd, a) {} Item_func_geometry_from_text(THD *thd, Item *a, Item *srid): @@@ -246,76 -84,60 +246,78 @@@ public }; -class Item_func_as_wkt: public Item_str_ascii_func +class Item_func_as_wkt: public Item_str_ascii_func_args_geometry { public: - Item_func_as_wkt(THD *thd, Item *a): Item_str_ascii_func(thd, a) {} + Item_func_as_wkt(THD *thd, Item *a) + :Item_str_ascii_func_args_geometry(thd, a) {} const char *func_name() const { return "st_astext"; } String *val_str_ascii(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_as_wkt>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_as_wkt>(thd, this); } }; -class Item_func_as_wkb: public Item_geometry_func +class Item_func_as_wkb: public Item_binary_func_args_geometry { public: - Item_func_as_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {} + Item_func_as_wkb(THD *thd, Item *a) + :Item_binary_func_args_geometry(thd, a) {} const char *func_name() const { return "st_aswkb"; } String *val_str(String *); - enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_as_wkb>(thd, mem_root, this); } + const Type_handler *type_handler() const { return &type_handler_long_blob; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + collation.set(&my_charset_bin); + decimals=0; + max_length= (uint32) UINT_MAX32; + maybe_null= 1; ++ return FALSE; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_as_wkb>(thd, this); } }; -class Item_func_as_geojson: public Item_str_ascii_func +class Item_func_as_geojson: public Item_str_ascii_func_args_geometry { + bool check_arguments() const + { + // TODO: check with Alexey, for better args[1] and args[2] type control + return Item_str_ascii_func_args_geometry::check_arguments() || + check_argument_types_traditional_scalar(1, MY_MIN(3, arg_count)); + } public: - Item_func_as_geojson(THD *thd, Item *js): Item_str_ascii_func(thd, js) {} - Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits): - Item_str_ascii_func(thd, js, max_dec_digits) {} - Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits, Item *opt): - Item_str_ascii_func(thd, js, max_dec_digits, opt) {} + Item_func_as_geojson(THD *thd, Item *js) + :Item_str_ascii_func_args_geometry(thd, js) {} + Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits) + :Item_str_ascii_func_args_geometry(thd, js, max_dec_digits) {} + Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits, Item *opt) + :Item_str_ascii_func_args_geometry(thd, js, max_dec_digits, opt) {} const char *func_name() const { return "st_asgeojson"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); String *val_str_ascii(String *); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_as_geojson>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_as_geojson>(thd, this); } }; -class Item_func_geometry_type: public Item_str_ascii_func +class Item_func_geometry_type: public Item_str_ascii_func_args_geometry { public: - Item_func_geometry_type(THD *thd, Item *a): Item_str_ascii_func(thd, a) {} + Item_func_geometry_type(THD *thd, Item *a) + :Item_str_ascii_func_args_geometry(thd, a) {} String *val_str_ascii(String *); const char *func_name() const { return "st_geometrytype"; } - void fix_length_and_dec() + bool fix_length_and_dec() { // "GeometryCollection" is the longest fix_length_and_charset(20, default_charset()); maybe_null= 1; + return FALSE; }; - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_geometry_type>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_geometry_type>(thd, this); } }; @@@ -720,47 -508,44 +725,47 @@@ public }; -class Item_func_isempty: public Item_bool_func +class Item_func_isempty: public Item_bool_func_args_geometry { public: - Item_func_isempty(THD *thd, Item *a): Item_bool_func(thd, a) {} + Item_func_isempty(THD *thd, Item *a) + :Item_bool_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_isempty"; } - void fix_length_and_dec() { maybe_null= 1; } + bool fix_length_and_dec() { maybe_null= 1; return FALSE; } bool need_parentheses_in_default() { return false; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_isempty>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_isempty>(thd, this); } }; -class Item_func_issimple: public Item_int_func +class Item_func_issimple: public Item_long_func_args_geometry { Gcalc_heap collector; Gcalc_function func; Gcalc_scan_iterator scan_it; String tmp; public: - Item_func_issimple(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_issimple(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_issimple"; } - void fix_length_and_dec() { decimals=0; max_length=2; } + bool fix_length_and_dec() { decimals=0; max_length=2; return FALSE; } uint decimal_precision() const { return 1; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_issimple>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_issimple>(thd, this); } }; -class Item_func_isclosed: public Item_int_func +class Item_func_isclosed: public Item_long_func_args_geometry { public: - Item_func_isclosed(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_isclosed(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_isclosed"; } - void fix_length_and_dec() { decimals=0; max_length=2; } + bool fix_length_and_dec() { decimals=0; max_length=2; return FALSE; } uint decimal_precision() const { return 1; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_isclosed>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_isclosed>(thd, this); } }; class Item_func_isring: public Item_func_issimple @@@ -769,107 -554,115 +774,113 @@@ public Item_func_isring(THD *thd, Item *a): Item_func_issimple(thd, a) {} longlong val_int(); const char *func_name() const { return "st_isring"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_isring>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_isring>(thd, this); } }; -class Item_func_dimension: public Item_int_func +class Item_func_dimension: public Item_long_func_args_geometry { - String value; public: - Item_func_dimension(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_dimension(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_dimension"; } - void fix_length_and_dec() { max_length= 10; maybe_null= 1; } + bool fix_length_and_dec() { max_length= 10; maybe_null= 1; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_dimension>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_dimension>(thd, this); } }; -class Item_func_x: public Item_real_func + +class Item_func_x: public Item_real_func_args_geometry { - String value; public: - Item_func_x(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_x(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_x"; } - void fix_length_and_dec() - { - Item_real_func::fix_length_and_dec(); - maybe_null= 1; + bool fix_length_and_dec() + { + if (Item_real_func::fix_length_and_dec()) + return TRUE; + maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_x>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_x>(thd, this); } }; -class Item_func_y: public Item_real_func +class Item_func_y: public Item_real_func_args_geometry { - String value; public: - Item_func_y(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_y(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_y"; } - void fix_length_and_dec() - { - Item_real_func::fix_length_and_dec(); - maybe_null= 1; + bool fix_length_and_dec() + { + if (Item_real_func::fix_length_and_dec()) + return TRUE; + maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_y>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_y>(thd, this); } }; -class Item_func_numgeometries: public Item_int_func +class Item_func_numgeometries: public Item_long_func_args_geometry { - String value; public: - Item_func_numgeometries(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_numgeometries(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_numgeometries"; } - void fix_length_and_dec() { max_length= 10; maybe_null= 1; } + bool fix_length_and_dec() { max_length= 10; maybe_null= 1; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_numgeometries>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_numgeometries>(thd, this); } }; -class Item_func_numinteriorring: public Item_int_func +class Item_func_numinteriorring: public Item_long_func_args_geometry { - String value; public: - Item_func_numinteriorring(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_numinteriorring(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_numinteriorrings"; } - void fix_length_and_dec() { max_length= 10; maybe_null= 1; } + bool fix_length_and_dec() { max_length= 10; maybe_null= 1; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_numinteriorring>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_numinteriorring>(thd, this); } }; -class Item_func_numpoints: public Item_int_func +class Item_func_numpoints: public Item_long_func_args_geometry { - String value; public: - Item_func_numpoints(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_numpoints(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "st_numpoints"; } - void fix_length_and_dec() { max_length= 10; maybe_null= 1; } + bool fix_length_and_dec() { max_length= 10; maybe_null= 1; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_numpoints>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_numpoints>(thd, this); } }; -class Item_func_area: public Item_real_func +class Item_func_area: public Item_real_func_args_geometry { - String value; public: - Item_func_area(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_area(THD *thd, Item *a): Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_area"; } - void fix_length_and_dec() - { - Item_real_func::fix_length_and_dec(); - maybe_null= 1; + bool fix_length_and_dec() + { + if (Item_real_func::fix_length_and_dec()) + return TRUE; + maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_area>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_area>(thd, this); } }; @@@ -877,30 -670,31 +888,32 @@@ class Item_func_glength: public Item_re { String value; public: - Item_func_glength(THD *thd, Item *a): Item_real_func(thd, a) {} + Item_func_glength(THD *thd, Item *a) + :Item_real_func_args_geometry(thd, a) {} double val_real(); const char *func_name() const { return "st_length"; } - void fix_length_and_dec() - { - Item_real_func::fix_length_and_dec(); - maybe_null= 1; + bool fix_length_and_dec() + { + if (Item_real_func::fix_length_and_dec()) + return TRUE; + maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_glength>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_glength>(thd, this); } }; -class Item_func_srid: public Item_int_func +class Item_func_srid: public Item_long_func_args_geometry { - String value; public: - Item_func_srid(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_srid(THD *thd, Item *a) + :Item_long_func_args_geometry(thd, a) {} longlong val_int(); const char *func_name() const { return "srid"; } - void fix_length_and_dec() { max_length= 10; maybe_null= 1; } + bool fix_length_and_dec() { max_length= 10; maybe_null= 1; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_srid>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_srid>(thd, this); } }; @@@ -939,12 -731,11 +952,12 @@@ public #ifndef DBUG_OFF -class Item_func_gis_debug: public Item_int_func +class Item_func_gis_debug: public Item_long_func { public: - Item_func_gis_debug(THD *thd, Item *a): Item_int_func(thd, a) + Item_func_gis_debug(THD *thd, Item *a): Item_long_func(thd, a) { null_value= false; } - void fix_length_and_dec() { fix_char_length(10); } ++ bool fix_length_and_dec() { fix_char_length(10); return FALSE; } const char *func_name() const { return "st_gis_debug"; } longlong val_int(); bool check_vcol_func_processor(void *arg) diff --cc sql/item_inetfunc.h index d934cef43dd,670dce3da9f..024ff8ce4f0 --- a/sql/item_inetfunc.h +++ b/sql/item_inetfunc.h @@@ -24,23 -24,22 +24,24 @@@ Item_func_inet_aton implements INET_ATON() SQL-function. *************************************************************************/ -class Item_func_inet_aton : public Item_int_func +class Item_func_inet_aton : public Item_longlong_func { + bool check_arguments() const + { return check_argument_types_can_return_text(0, arg_count); } public: - Item_func_inet_aton(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_inet_aton(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int(); const char *func_name() const { return "inet_aton"; } - void fix_length_and_dec() + bool fix_length_and_dec() { decimals= 0; max_length= 21; maybe_null= 1; unsigned_flag= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_inet_aton>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_inet_aton>(thd, this); } }; @@@ -60,9 -59,10 +61,10 @@@ public decimals= 0; fix_length_and_charset(3 * 8 + 7, default_charset()); maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_inet_ntoa>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_inet_ntoa>(thd, this); } }; @@@ -129,9 -129,10 +131,10 @@@ public decimals= 0; fix_length_and_charset(16, &my_charset_bin); maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_inet6_aton>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_inet6_aton>(thd, this); } protected: virtual bool calc_value(const String *arg, String *buffer); @@@ -163,9 -164,10 +166,10 @@@ public fix_length_and_charset(8 * 4 + 7, default_charset()); maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_inet6_ntoa>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_inet6_ntoa>(thd, this); } protected: virtual bool calc_value(const String *arg, String *buffer); diff --cc sql/item_jsonfunc.cc index e67357000da,72aeac5b930..52042c56fcc --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@@ -388,11 -388,13 +388,13 @@@ longlong Item_func_json_valid::val_int( } - void Item_func_json_exists::fix_length_and_dec() + bool Item_func_json_exists::fix_length_and_dec() { - Item_bool_func::fix_length_and_dec(); - if (Item_int_func::fix_length_and_dec()) ++ if (Item_bool_func::fix_length_and_dec()) + return TRUE; maybe_null= 1; path.set_constant_flag(args[1]->const_item()); + return FALSE; } @@@ -944,7 -950,7 +950,7 @@@ bool Item_func_json_contains::fix_lengt maybe_null= 1; if (arg_count > 2) path.set_constant_flag(args[2]->const_item()); - Item_bool_func::fix_length_and_dec(); - return Item_int_func::fix_length_and_dec(); ++ return Item_bool_func::fix_length_and_dec(); } @@@ -1196,7 -1202,7 +1202,7 @@@ bool Item_func_json_contains_path::fix_ ooa_parsed= FALSE; maybe_null= 1; mark_constant_paths(paths, args+2, arg_count-2); - Item_bool_func::fix_length_and_dec(); - return Item_int_func::fix_length_and_dec(); ++ return Item_bool_func::fix_length_and_dec(); } @@@ -2129,7 -2135,7 +2137,8 @@@ bool Item_func_json_length::fix_length_ if (arg_count > 1) path.set_constant_flag(args[1]->const_item()); maybe_null= 1; + max_length= 10; + return FALSE; } diff --cc sql/item_jsonfunc.h index 354de69eee4,f331ee3b582..af0995b9605 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@@ -46,16 -46,19 +46,18 @@@ protected String tmp_value; public: - Item_func_json_valid(THD *thd, Item *json) : Item_int_func(thd, json) {} + Item_func_json_valid(THD *thd, Item *json) : Item_bool_func(thd, json) {} longlong val_int(); const char *func_name() const { return "json_valid"; } - void fix_length_and_dec() + bool fix_length_and_dec() { - Item_bool_func::fix_length_and_dec(); - if (Item_int_func::fix_length_and_dec()) ++ if (Item_bool_func::fix_length_and_dec()) + return TRUE; maybe_null= 1; + return FALSE; } - bool is_bool_type() { return true; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_valid>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_valid>(thd, this); } }; @@@ -67,11 -70,12 +69,11 @@@ protected public: Item_func_json_exists(THD *thd, Item *js, Item *i_path): - Item_int_func(thd, js, i_path) {} + Item_bool_func(thd, js, i_path) {} const char *func_name() const { return "json_exists"; } - void fix_length_and_dec(); - bool is_bool_type() { return true; } + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_exists>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_exists>(thd, this); } longlong val_int(); }; @@@ -86,11 -90,11 +88,11 @@@ public Item_func_json_value(THD *thd, Item *js, Item *i_path): Item_str_func(thd, js, i_path) {} const char *func_name() const { return "json_value"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); String *val_str(String *); virtual bool check_and_get_value(json_engine_t *je, String *res, int *error); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_value>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_value>(thd, this); } }; @@@ -115,10 -119,10 +117,10 @@@ protected public: Item_func_json_quote(THD *thd, Item *s): Item_str_func(thd, s) {} const char *func_name() const { return "json_quote"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); String *val_str(String *); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_quote>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_quote>(thd, this); } }; @@@ -130,10 -134,10 +132,10 @@@ protected public: Item_func_json_unquote(THD *thd, Item *s): Item_str_func(thd, s) {} const char *func_name() const { return "json_unquote"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); String *val_str(String *); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_unquote>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_unquote>(thd, this); } }; @@@ -183,12 -187,12 +185,12 @@@ protected String tmp_val, *val; public: Item_func_json_contains(THD *thd, List<Item> &list): - Item_int_func(thd, list) {} + Item_bool_func(thd, list) {} const char *func_name() const { return "json_contains"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_contains>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_contains>(thd, this); } }; @@@ -204,14 -208,14 +206,14 @@@ protected public: Item_func_json_contains_path(THD *thd, List<Item> &list): - Item_int_func(thd, list), tmp_paths(0) {} + Item_bool_func(thd, list), tmp_paths(0) {} const char *func_name() const { return "json_contains_path"; } bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); void cleanup(); longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_contains_path>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_contains_path>(thd, this); } }; @@@ -227,10 -231,10 +229,10 @@@ public Item_str_func(thd, list) {} String *val_str(String *); bool is_json_type() { return true; } - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "json_array"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_array>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_array>(thd, this); } }; @@@ -307,12 -305,12 +309,12 @@@ protected String tmp_path; public: Item_func_json_length(THD *thd, List<Item> &list): - Item_int_func(thd, list) {} + Item_long_func(thd, list) {} const char *func_name() const { return "json_length"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_length>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_length>(thd, this); } }; @@@ -323,12 -319,11 +325,12 @@@ class Item_func_json_depth: public Item protected: String tmp_js; public: - Item_func_json_depth(THD *thd, Item *js): Item_int_func(thd, js) {} + Item_func_json_depth(THD *thd, Item *js): Item_long_func(thd, js) {} const char *func_name() const { return "json_depth"; } - void fix_length_and_dec() { max_length= 10; } ++ bool fix_length_and_dec() { max_length= 10; return FALSE; } longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_depth>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_depth>(thd, this); } }; @@@ -339,10 -334,10 +341,10 @@@ protected public: Item_func_json_type(THD *thd, Item *js): Item_str_func(thd, js) {} const char *func_name() const { return "json_type"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); String *val_str(String *); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_type>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_type>(thd, this); } }; @@@ -395,10 -390,10 +397,10 @@@ public Item_func_json_keys(THD *thd, List<Item> &list): Item_str_func(thd, list) {} const char *func_name() const { return "json_keys"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); String *val_str(String *); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_keys>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_keys>(thd, this); } }; @@@ -419,11 -414,11 +421,11 @@@ public Item_json_str_multipath(thd, list) {} const char *func_name() const { return "json_search"; } bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); String *val_str(String *); uint get_n_paths() const { return arg_count > 4 ? arg_count - 4 : 0; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_json_search>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_json_search>(thd, this); } }; diff --cc sql/item_strfunc.cc index 6af49d494d4,87c766340c7..c914c6cbdf8 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@@ -652,25 -636,7 +658,25 @@@ null } +bool Item_func_concat::append_value(THD *thd, String *res, const String *app) +{ + uint concat_len; + if ((concat_len= res->length() + app->length()) > + thd->variables.max_allowed_packet) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_ALLOWED_PACKET_OVERFLOWED, + ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(), + thd->variables.max_allowed_packet); + return true; + } + DBUG_ASSERT(!res->uses_buffer_owned_by(app)); + DBUG_ASSERT(!app->uses_buffer_owned_by(res)); + return realloc_result(res, concat_len) || res->append(*app); +} + + - void Item_func_concat::fix_length_and_dec() + bool Item_func_concat::fix_length_and_dec() { ulonglong char_length= 0; @@@ -1102,11 -1070,12 +1110,13 @@@ String *Item_func_reverse::val_str(Stri } - void Item_func_reverse::fix_length_and_dec() + bool Item_func_reverse::fix_length_and_dec() { -- agg_arg_charsets_for_string_result(collation, args, 1); ++ if (agg_arg_charsets_for_string_result(collation, args, 1)) ++ return TRUE; DBUG_ASSERT(collation.collation != NULL); fix_char_length(args[0]->max_char_length()); + return FALSE; } /** @@@ -2417,10 -2374,10 +2445,11 @@@ bool Item_func_current_role::fix_fields return 0; } - void Item_func_soundex::fix_length_and_dec() + bool Item_func_soundex::fix_length_and_dec() { uint32 char_length= args[0]->max_char_length(); -- agg_arg_charsets_for_string_result(collation, args, 1); ++ if (agg_arg_charsets_for_string_result(collation, args, 1)) ++ return TRUE; DBUG_ASSERT(collation.collation != NULL); set_if_bigger(char_length, 4); fix_char_length(char_length); @@@ -2581,16 -2539,35 +2611,17 @@@ String *Item_func_soundex::val_str(Stri const int FORMAT_MAX_DECIMALS= 30; - void Item_func_format::fix_length_and_dec() -MY_LOCALE *Item_func_format::get_locale(Item *item) -{ - DBUG_ASSERT(arg_count == 3); - String tmp, *locale_name= args[2]->val_str_ascii(&tmp); - MY_LOCALE *lc; - if (!locale_name || - !(lc= my_locale_by_name(locale_name->c_ptr_safe()))) - { - THD *thd= current_thd; - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_UNKNOWN_LOCALE, - ER_THD(thd, ER_UNKNOWN_LOCALE), - locale_name ? locale_name->c_ptr_safe() : "NULL"); - lc= &my_locale_en_US; - } - return lc; -} - + bool Item_func_format::fix_length_and_dec() { uint32 char_length= args[0]->max_char_length(); uint32 max_sep_count= (char_length / 3) + (decimals ? 1 : 0) + /*sign*/1; collation.set(default_charset()); fix_char_length(char_length + max_sep_count + decimals); if (arg_count == 3) - locale= args[2]->basic_const_item() ? get_locale(args[2]) : NULL; + locale= args[2]->basic_const_item() ? args[2]->locale_from_val_str() : NULL; else locale= &my_locale_en_US; /* Two arguments */ + return FALSE; } @@@ -3123,23 -3084,11 +3160,23 @@@ err } - void Item_func_pad::fix_length_and_dec() -bool Item_func_rpad::fix_length_and_dec() ++bool Item_func_pad::fix_length_and_dec() { - // Handle character set for args[0] and args[2]. - if (agg_arg_charsets_for_string_result(collation, &args[0], 2, 2)) - return TRUE; + if (arg_count == 3) + { + // Handle character set for args[0] and args[2]. + if (agg_arg_charsets_for_string_result(collation, &args[0], 2, 2)) - return; ++ return TRUE; + } + else + { + if (agg_arg_charsets_for_string_result(collation, &args[0], 1, 1)) - return; ++ return TRUE; + pad_str.set_charset(collation.collation); + pad_str.length(0); + pad_str.append(" ", 1); + } + if (args[1]->const_item()) { ulonglong char_length= (ulonglong) args[1]->val_int(); @@@ -3436,17 -3392,32 +3475,18 @@@ String *Item_func_set_collation::val_st return str; } - void Item_func_set_collation::fix_length_and_dec() + bool Item_func_set_collation::fix_length_and_dec() { - CHARSET_INFO *set_collation; - const char *colname; - String tmp, *str= args[1]->val_str(&tmp); - colname= str->c_ptr(); - if (colname == binary_keyword) - set_collation= get_charset_by_csname(args[0]->collation.collation->csname, - MY_CS_BINSORT,MYF(0)); - else - { - if (!(set_collation= mysqld_collation_get_by_name(colname))) - return TRUE; - } - - if (!set_collation || - !my_charset_same(args[0]->collation.collation,set_collation)) + if (!my_charset_same(args[0]->collation.collation, m_set_collation)) { my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), - colname, args[0]->collation.collation->csname); + m_set_collation->name, args[0]->collation.collation->csname); - return; + return TRUE; } - collation.set(set_collation, DERIVATION_EXPLICIT, + collation.set(m_set_collation, DERIVATION_EXPLICIT, args[0]->collation.repertoire); max_length= args[0]->max_length; + return FALSE; } @@@ -3501,12 -3488,13 +3541,13 @@@ bool Item_func_weight_string::fix_lengt */ if (!(max_length= result_length)) { - uint char_length; + size_t char_length; char_length= ((cs->state & MY_CS_STRNXFRM_BAD_NWEIGHTS) || !nweights) ? args[0]->max_char_length() : nweights * cs->levels_for_order; - max_length= cs->coll->strnxfrmlen(cs, char_length * cs->mbmaxlen); + max_length= (uint32)cs->coll->strnxfrmlen(cs, char_length * cs->mbmaxlen); } maybe_null= 1; + return FALSE; } @@@ -5204,23 -5203,3 +5247,24 @@@ null my_free(names); return NULL; } + +Item_temptable_rowid::Item_temptable_rowid(TABLE *table_arg) + : Item_str_func(table_arg->in_use), table(table_arg) +{ + max_length= table->file->ref_length; +} + - void Item_temptable_rowid::fix_length_and_dec() ++bool Item_temptable_rowid::fix_length_and_dec() +{ + used_tables_cache= table->map; + const_item_cache= false; ++ return FALSE; +} + +String *Item_temptable_rowid::val_str(String *str) +{ + if (!((null_value= table->null_row))) + table->file->position(table->record[0]); + str_value.set((char*)(table->file->ref), max_length, &my_charset_bin); + return &str_value; +} diff --cc sql/item_strfunc.h index eb084c3f58d,a908aba2d2f..29af0b43d9d --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@@ -144,13 -145,14 +144,14 @@@ class Item_func_md5 :public Item_str_as public: Item_func_md5(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *); - void fix_length_and_dec() + bool fix_length_and_dec() { fix_length_and_charset(32, default_charset()); + return FALSE; } const char *func_name() const { return "md5"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_md5>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_md5>(thd, this); } }; @@@ -159,10 -161,10 +160,10 @@@ class Item_func_sha :public Item_str_as public: Item_func_sha(THD *thd, Item *a): Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "sha"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_sha>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_sha>(thd, this); } }; class Item_func_sha2 :public Item_str_ascii_checksum_func @@@ -171,10 -173,10 +172,10 @@@ public Item_func_sha2(THD *thd, Item *a, Item *b) :Item_str_ascii_checksum_func(thd, a, b) {} String *val_str_ascii(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "sha2"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_sha2>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_sha2>(thd, this); } }; class Item_func_to_base64 :public Item_str_ascii_checksum_func @@@ -184,10 -186,10 +185,10 @@@ public Item_func_to_base64(THD *thd, Item *a) :Item_str_ascii_checksum_func(thd, a) {} String *val_str_ascii(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "to_base64"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_to_base64>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_to_base64>(thd, this); } }; class Item_func_from_base64 :public Item_str_binary_checksum_func @@@ -197,10 -199,10 +198,10 @@@ public Item_func_from_base64(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) { } String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "from_base64"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_from_base64>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_from_base64>(thd, this); } }; #include <my_crypt.h> @@@ -224,10 -226,10 +225,10 @@@ class Item_func_aes_encrypt :public Ite public: Item_func_aes_encrypt(THD *thd, Item *a, Item *b) :Item_aes_crypt(thd, a, b) {} - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "aes_encrypt"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_aes_encrypt>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_aes_encrypt>(thd, this); } }; class Item_func_aes_decrypt :public Item_aes_crypt @@@ -235,10 -237,10 +236,10 @@@ public: Item_func_aes_decrypt(THD *thd, Item *a, Item *b): Item_aes_crypt(thd, a, b) {} - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "aes_decrypt"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_aes_decrypt>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_aes_decrypt>(thd, this); } }; @@@ -259,35 -252,12 +260,35 @@@ public Item_func_concat(THD *thd, List<Item> &list): Item_str_func(thd, list) {} Item_func_concat(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "concat"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_concat>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_concat>(thd, this); } +}; + + +/* + This class handles the || operator in sql_mode=ORACLE. + Unlike the traditional MariaDB concat(), it treats NULL arguments as ''. +*/ +class Item_func_concat_operator_oracle :public Item_func_concat +{ +public: + Item_func_concat_operator_oracle(THD *thd, List<Item> &list) + :Item_func_concat(thd, list) + { } + Item_func_concat_operator_oracle(THD *thd, Item *a, Item *b) + :Item_func_concat(thd, a, b) + { } + String *val_str(String *); + const char *func_name() const { return "concat_operator_oracle"; } + Item *get_copy(THD *thd) + { + return get_item_copy<Item_func_concat_operator_oracle>(thd, this); + } }; + class Item_func_decode_histogram :public Item_str_func { public: @@@ -299,10 -269,11 +300,11 @@@ collation.set(system_charset_info); max_length= MAX_BLOB_WIDTH; maybe_null= 1; + return FALSE; } const char *func_name() const { return "decode_histogram"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_decode_histogram>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_decode_histogram>(thd, this); } }; class Item_func_concat_ws :public Item_str_func @@@ -311,11 -282,11 +313,11 @@@ public: Item_func_concat_ws(THD *thd, List<Item> &list): Item_str_func(thd, list) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "concat_ws"; } table_map not_null_tables() const { return 0; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_concat_ws>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_concat_ws>(thd, this); } }; class Item_func_reverse :public Item_str_func @@@ -324,10 -295,10 +326,10 @@@ public: Item_func_reverse(THD *thd, Item *a): Item_str_func(thd, a) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "reverse"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_reverse>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_reverse>(thd, this); } }; @@@ -337,25 -308,11 +339,25 @@@ class Item_func_replace :public Item_st public: Item_func_replace(THD *thd, Item *org, Item *find, Item *replace): Item_str_func(thd, org, find, replace) {} - String *val_str(String *); + String *val_str(String *to) { return val_str_internal(to, NULL); }; - void fix_length_and_dec(); + bool fix_length_and_dec(); + String *val_str_internal(String *str, String *empty_string_for_null); const char *func_name() const { return "replace"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_replace>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_replace>(thd, this); } +}; + + +class Item_func_replace_oracle :public Item_func_replace +{ + String tmp_emtpystr; +public: + Item_func_replace_oracle(THD *thd, Item *org, Item *find, Item *replace): + Item_func_replace(thd, org, find, replace) {} + String *val_str(String *to) { return val_str_internal(to, &tmp_emtpystr); }; + const char *func_name() const { return "replace_oracle"; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_replace_oracle>(thd, this); } }; @@@ -378,9 -335,9 +380,9 @@@ public } String *val_str(String *str); bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "regexp_replace"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0;} + Item *get_copy(THD *thd) { return 0;} }; @@@ -400,9 -357,9 +402,9 @@@ public } String *val_str(String *str); bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "regexp_substr"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } + Item *get_copy(THD *thd) { return 0; } }; @@@ -414,10 -371,10 +416,10 @@@ public Item *new_str): Item_str_func(thd, org, start, length, new_str) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "insert"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_insert>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_insert>(thd, this); } }; @@@ -438,9 -395,9 +440,9 @@@ class Item_func_lcase :public Item_str_ public: Item_func_lcase(THD *thd, Item *item): Item_str_conv(thd, item) {} const char *func_name() const { return "lcase"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_lcase>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_lcase>(thd, this); } }; class Item_func_ucase :public Item_str_conv @@@ -448,9 -405,9 +450,9 @@@ public: Item_func_ucase(THD *thd, Item *item): Item_str_conv(thd, item) {} const char *func_name() const { return "ucase"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_ucase>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_ucase>(thd, this); } }; @@@ -460,10 -417,10 +462,10 @@@ class Item_func_left :public Item_str_f public: Item_func_left(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "left"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_left>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_left>(thd, this); } }; @@@ -473,50 -430,26 +475,51 @@@ class Item_func_right :public Item_str_ public: Item_func_right(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "right"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_right>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_right>(thd, this); } }; class Item_func_substr :public Item_str_func { String tmp_value; +protected: + virtual longlong get_position() { return args[1]->val_int(); } public: Item_func_substr(THD *thd, Item *a, Item *b): Item_str_func(thd, a, b) {} - Item_func_substr(THD *thd, Item *a, Item *b, Item *c): Item_str_func(thd, a, b, c) {} + Item_func_substr(THD *thd, Item *a, Item *b, Item *c): + Item_str_func(thd, a, b, c) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "substr"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_substr>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_substr>(thd, this); } }; +class Item_func_substr_oracle :public Item_func_substr +{ +protected: + longlong get_position() + { longlong pos= args[1]->val_int(); return pos == 0 ? 1 : pos; } + String *make_empty_result() + { null_value= 1; return NULL; } +public: + Item_func_substr_oracle(THD *thd, Item *a, Item *b): + Item_func_substr(thd, a, b) {} + Item_func_substr_oracle(THD *thd, Item *a, Item *b, Item *c): + Item_func_substr(thd, a, b, c) {} - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - Item_func_substr::fix_length_and_dec(); ++ bool res= Item_func_substr::fix_length_and_dec(); + maybe_null= true; ++ return res; + } + const char *func_name() const { return "substr_oracle"; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_substr_oracle>(thd, this); } +}; class Item_func_substr_index :public Item_str_func { @@@ -525,10 -458,10 +528,10 @@@ public Item_func_substr_index(THD *thd, Item *a,Item *b,Item *c): Item_str_func(thd, a, b, c) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "substring_index"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_substr_index>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_substr_index>(thd, this); } }; @@@ -565,29 -494,8 +568,30 @@@ public const char *func_name() const { return "trim"; } void print(String *str, enum_query_type query_type); virtual const char *mode_name() const { return "both"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_trim>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_trim>(thd, this); } +}; + + +class Item_func_trim_oracle :public Item_func_trim +{ +protected: + String *make_empty_result() + { null_value= 1; return NULL; } + const char *func_name_ext() const { return "_oracle"; } +public: + Item_func_trim_oracle(THD *thd, Item *a, Item *b): + Item_func_trim(thd, a, b) {} + Item_func_trim_oracle(THD *thd, Item *a): Item_func_trim(thd, a) {} + const char *func_name() const { return "trim_oracle"; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - Item_func_trim::fix_length_and_dec(); ++ bool res= Item_func_trim::fix_length_and_dec(); + maybe_null= true; ++ return res; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_trim_oracle>(thd, this); } }; @@@ -599,29 -507,8 +603,30 @@@ public String *val_str(String *); const char *func_name() const { return "ltrim"; } const char *mode_name() const { return "leading"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_ltrim>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_ltrim>(thd, this); } +}; + + +class Item_func_ltrim_oracle :public Item_func_ltrim +{ +protected: + String *make_empty_result() + { null_value= 1; return NULL; } + const char *func_name_ext() const { return "_oracle"; } +public: + Item_func_ltrim_oracle(THD *thd, Item *a, Item *b): + Item_func_ltrim(thd, a, b) {} + Item_func_ltrim_oracle(THD *thd, Item *a): Item_func_ltrim(thd, a) {} + const char *func_name() const { return "ltrim_oracle"; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - Item_func_ltrim::fix_length_and_dec(); ++ bool res= Item_func_ltrim::fix_length_and_dec(); + maybe_null= true; ++ return res; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_ltrim_oracle>(thd, this); } }; @@@ -638,26 -525,6 +643,27 @@@ public }; +class Item_func_rtrim_oracle :public Item_func_rtrim +{ +protected: + String *make_empty_result() + { null_value= 1; return NULL; } + const char *func_name_ext() const { return "_oracle"; } +public: + Item_func_rtrim_oracle(THD *thd, Item *a, Item *b): + Item_func_rtrim(thd, a, b) {} + Item_func_rtrim_oracle(THD *thd, Item *a): Item_func_rtrim(thd, a) {} + const char *func_name() const { return "rtrim_oracle"; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - Item_func_rtrim::fix_length_and_dec(); ++ bool res= Item_func_rtrim::fix_length_and_dec(); + maybe_null= true; ++ return res; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_rtrim_oracle>(thd, this); } +}; + /* Item_func_password -- new (4.1.1) PASSWORD() function implementation. Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new @@@ -712,10 -580,11 +719,11 @@@ public maybe_null=1; /* 9 = MAX ((8- (arg_len % 8)) + 1) */ max_length = args[0]->max_length + 9; + return FALSE; } const char *func_name() const { return "des_encrypt"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_des_encrypt>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_des_encrypt>(thd, this); } }; class Item_func_des_decrypt :public Item_str_binary_checksum_func @@@ -734,10 -603,11 +742,11 @@@ public max_length= args[0]->max_length; if (max_length >= 9U) max_length-= 9U; + return FALSE; } const char *func_name() const { return "des_decrypt"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_des_decrypt>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_des_decrypt>(thd, this); } }; @@@ -790,10 -660,10 +799,10 @@@ public Item_func_encode(THD *thd, Item *a, Item *seed_arg): Item_str_binary_checksum_func(thd, a, seed_arg) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "encode"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_encode>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_encode>(thd, this); } protected: virtual void crypto_transform(String *); private: @@@ -847,29 -718,8 +857,30 @@@ public } const char *func_name() const { return "database"; } const char *fully_qualified_func_name() const { return "database()"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_database>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_database>(thd, this); } +}; + + +class Item_func_sqlerrm :public Item_func_sysconst +{ +public: + Item_func_sqlerrm(THD *thd): Item_func_sysconst(thd) {} + String *val_str(String *); + const char *func_name() const { return "SQLERRM"; } + const char *fully_qualified_func_name() const { return "SQLERRM"; } + void print(String *str, enum_query_type query_type) + { + str->append(func_name()); + } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + max_length= 512 * system_charset_info->mbmaxlen; + null_value= maybe_null= false; ++ return FALSE; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_sqlerrm>(thd, this); } }; @@@ -961,10 -815,10 +976,10 @@@ class Item_func_soundex :public Item_st public: Item_func_soundex(THD *thd, Item *a): Item_str_func(thd, a) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "soundex"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_soundex>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_soundex>(thd, this); } }; @@@ -975,10 -829,10 +990,10 @@@ public double val_real(); longlong val_int(); String *val_str(String *str); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "elt"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_elt>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_elt>(thd, this); } }; @@@ -989,10 -843,10 +1004,10 @@@ class Item_func_make_set :public Item_s public: Item_func_make_set(THD *thd, List<Item> &list): Item_str_func(thd, list) {} String *val_str(String *str); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "make_set"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_make_set>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_make_set>(thd, this); } }; @@@ -1005,11 -859,12 +1020,11 @@@ public Item_func_format(THD *thd, Item *org, Item *dec, Item *lang): Item_str_ascii_func(thd, org, dec, lang) {} - MY_LOCALE *get_locale(Item *item); String *val_str_ascii(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "format"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_format>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_format>(thd, this); } }; @@@ -1021,35 -876,18 +1036,37 @@@ public Item_func_char(THD *thd, List<Item> &list, CHARSET_INFO *cs): Item_str_func(thd, list) { collation.set(cs); } + Item_func_char(THD *thd, Item *arg1, CHARSET_INFO *cs): + Item_str_func(thd, arg1) + { collation.set(cs); } String *val_str(String *); + void append_char(String * str, int32 num); - void fix_length_and_dec() + bool fix_length_and_dec() { max_length= arg_count * 4; + return FALSE; } const char *func_name() const { return "char"; } void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_char>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_char>(thd, this); } }; +class Item_func_chr :public Item_func_char +{ +public: + Item_func_chr(THD *thd, Item *arg1, CHARSET_INFO *cs): + Item_func_char(thd, arg1, cs) {} + String *val_str(String *); - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + max_length= 4; ++ return FALSE; + } + const char *func_name() const { return "chr"; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_chr>(thd, this); } +}; class Item_func_repeat :public Item_str_func { @@@ -1058,10 -896,10 +1075,10 @@@ public Item_func_repeat(THD *thd, Item *arg1, Item *arg2): Item_str_func(thd, arg1, arg2) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "repeat"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_repeat>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_repeat>(thd, this); } }; @@@ -1070,10 -908,10 +1087,10 @@@ class Item_func_space :public Item_str_ public: Item_func_space(THD *thd, Item *arg1): Item_str_func(thd, arg1) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "space"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_space>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_space>(thd, this); } }; @@@ -1094,84 -932,31 +1111,86 @@@ public }; -class Item_func_rpad :public Item_str_func +class Item_func_pad: public Item_str_func { - String tmp_value, rpad_str; +protected: + String tmp_value, pad_str; public: - Item_func_rpad(THD *thd, Item *arg1, Item *arg2, Item *arg3): + Item_func_pad(THD *thd, Item *arg1, Item *arg2, Item *arg3): Item_str_func(thd, arg1, arg2, arg3) {} - String *val_str(String *); + Item_func_pad(THD *thd, Item *arg1, Item *arg2): + Item_str_func(thd, arg1, arg2) {} - void fix_length_and_dec(); + bool fix_length_and_dec(); +}; + + +class Item_func_rpad :public Item_func_pad +{ +public: + Item_func_rpad(THD *thd, Item *arg1, Item *arg2, Item *arg3): + Item_func_pad(thd, arg1, arg2, arg3) {} + Item_func_rpad(THD *thd, Item *arg1, Item *arg2): + Item_func_pad(thd, arg1, arg2) {} + String *val_str(String *); const char *func_name() const { return "rpad"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_rpad>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_rpad>(thd, this); } }; -class Item_func_lpad :public Item_str_func +class Item_func_rpad_oracle :public Item_func_rpad +{ + String *make_empty_result() + { null_value= 1; return NULL; } +public: + Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): + Item_func_rpad(thd, arg1, arg2, arg3) {} + Item_func_rpad_oracle(THD *thd, Item *arg1, Item *arg2): + Item_func_rpad(thd, arg1, arg2) {} - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - Item_func_rpad::fix_length_and_dec(); ++ bool res= Item_func_rpad::fix_length_and_dec(); + maybe_null= true; ++ return res; + } + const char *func_name() const { return "rpad_oracle"; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_rpad_oracle>(thd, this); } +}; + + +class Item_func_lpad :public Item_func_pad { - String tmp_value, lpad_str; public: Item_func_lpad(THD *thd, Item *arg1, Item *arg2, Item *arg3): - Item_str_func(thd, arg1, arg2, arg3) {} + Item_func_pad(thd, arg1, arg2, arg3) {} + Item_func_lpad(THD *thd, Item *arg1, Item *arg2): + Item_func_pad(thd, arg1, arg2) {} String *val_str(String *); - bool fix_length_and_dec(); const char *func_name() const { return "lpad"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_lpad>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_lpad>(thd, this); } +}; + + +class Item_func_lpad_oracle :public Item_func_lpad +{ + String *make_empty_result() + { null_value= 1; return NULL; } +public: + Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2, Item *arg3): + Item_func_lpad(thd, arg1, arg2, arg3) {} + Item_func_lpad_oracle(THD *thd, Item *arg1, Item *arg2): + Item_func_lpad(thd, arg1, arg2) {} - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - Item_func_lpad::fix_length_and_dec(); ++ bool res= Item_func_lpad::fix_length_and_dec(); + maybe_null= true; ++ return res; + } + const char *func_name() const { return "lpad_oracle"; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_lpad_oracle>(thd, this); } }; @@@ -1187,44 -972,30 +1206,46 @@@ public collation.set(default_charset()); max_length=64; maybe_null= 1; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_conv>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_conv>(thd, this); } }; class Item_func_hex :public Item_str_ascii_checksum_func { +protected: String tmp_value; + /* + Calling arg[0]->type_handler() can be expensive on every row. + It's a virtual method, and in case if args[0] is a complex Item, + its type_handler() can call more virtual methods. + So let's cache it during fix_length_and_dec(). + */ + const Type_handler *m_arg0_type_handler; public: Item_func_hex(THD *thd, Item *a): - Item_str_ascii_checksum_func(thd, a) {} + Item_str_ascii_checksum_func(thd, a), m_arg0_type_handler(NULL) {} const char *func_name() const { return "hex"; } - String *val_str_ascii(String *); + String *val_str_ascii_from_val_int(String *str); + String *val_str_ascii_from_val_real(String *str); + String *val_str_ascii_from_val_str(String *str); + String *val_str_ascii(String *str) + { + DBUG_ASSERT(fixed); + return m_arg0_type_handler->Item_func_hex_val_str_ascii(this, str); + } - void fix_length_and_dec() + bool fix_length_and_dec() { - collation.set(default_charset()); + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); decimals=0; fix_char_length(args[0]->max_length * 2); + m_arg0_type_handler= args[0]->type_handler(); + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_hex>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_hex>(thd, this); } }; class Item_func_unhex :public Item_str_func @@@ -1243,9 -1014,10 +1264,10 @@@ public collation.set(&my_charset_bin); decimals=0; max_length=(1+args[0]->max_length)/2; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_unhex>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_unhex>(thd, this); } }; @@@ -1351,10 -1126,10 +1376,10 @@@ class Item_func_export_set: public Item Item_func_export_set(THD *thd, Item *a, Item *b, Item* c, Item* d, Item* e): Item_str_func(thd, a, b, c, d, e) {} String *val_str(String *str); - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "export_set"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_export_set>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_export_set>(thd, this); } }; @@@ -1371,9 -1146,10 +1396,10 @@@ public ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 + 2 * collation.collation->mbmaxlen; max_length= (uint32) MY_MIN(max_result_length, MAX_BLOB_WIDTH); + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_quote>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_quote>(thd, this); } }; class Item_func_conv_charset :public Item_str_func @@@ -1453,21 -1229,20 +1479,21 @@@ public return 1; return res; } - void fix_length_and_dec(); + bool fix_length_and_dec(); const char *func_name() const { return "convert"; } void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_conv_charset>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_conv_charset>(thd, this); } }; class Item_func_set_collation :public Item_str_func { + CHARSET_INFO *m_set_collation; public: - Item_func_set_collation(THD *thd, Item *a, Item *b): - Item_str_func(thd, a, b) {} + Item_func_set_collation(THD *thd, Item *a, CHARSET_INFO *set_collation): + Item_str_func(thd, a), m_set_collation(set_collation) {} String *val_str(String *); - void fix_length_and_dec(); + bool fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } enum precedence precedence() const { return COLLATE_PRECEDENCE; } @@@ -1555,36 -1331,33 +1582,36 @@@ public Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) { return this; } void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_weight_string>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_weight_string>(thd, this); } }; -class Item_func_crc32 :public Item_int_func +class Item_func_crc32 :public Item_long_func { + bool check_arguments() const + { return args[0]->check_type_can_return_str(func_name()); } String value; public: - Item_func_crc32(THD *thd, Item *a): Item_int_func(thd, a) + Item_func_crc32(THD *thd, Item *a): Item_long_func(thd, a) { unsigned_flag= 1; } const char *func_name() const { return "crc32"; } - void fix_length_and_dec() { max_length=10; } + bool fix_length_and_dec() { max_length=10; return FALSE; } longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_crc32>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_crc32>(thd, this); } }; -class Item_func_uncompressed_length : public Item_int_func +class Item_func_uncompressed_length : public Item_long_func_length { String value; public: - Item_func_uncompressed_length(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_uncompressed_length(THD *thd, Item *a) + :Item_long_func_length(thd, a) {} const char *func_name() const{return "uncompressed_length";} - void fix_length_and_dec() { max_length=10; maybe_null= true; } + bool fix_length_and_dec() { max_length=10; maybe_null= true; return FALSE; } longlong val_int(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_uncompressed_length>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_uncompressed_length>(thd, this); } }; #ifdef HAVE_COMPRESS @@@ -1599,11 -1372,15 +1626,15 @@@ class Item_func_compress: public Item_s public: Item_func_compress(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) {} - void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} + bool fix_length_and_dec() + { + max_length= (args[0]->max_length * 120) / 100 + 12; + return FALSE; + } const char *func_name() const{return "compress";} String *val_str(String *) ZLIB_DEPENDED_FUNCTION - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_compress>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_compress>(thd, this); } }; class Item_func_uncompress: public Item_str_binary_checksum_func @@@ -1612,11 -1389,15 +1643,15 @@@ public: Item_func_uncompress(THD *thd, Item *a) :Item_str_binary_checksum_func(thd, a) {} - void fix_length_and_dec(){ maybe_null= 1; max_length= MAX_BLOB_WIDTH; } + bool fix_length_and_dec() + { + maybe_null= 1; max_length= MAX_BLOB_WIDTH; + return FALSE; + } const char *func_name() const{return "uncompress";} String *val_str(String *) ZLIB_DEPENDED_FUNCTION - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_uncompress>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_uncompress>(thd, this); } }; @@@ -1691,9 -1473,10 +1727,10 @@@ public max_length= MAX_BLOB_WIDTH; maybe_null= 1; decimals= 0; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_dyncol_json>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_dyncol_json>(thd, this); } }; /* @@@ -1744,32 -1527,13 +1781,33 @@@ class Item_func_dyncol_list: public Ite public: Item_func_dyncol_list(THD *thd, Item *str): Item_str_func(thd, str) {collation.set(DYNCOL_UTF);} - void fix_length_and_dec() { maybe_null= 1; max_length= MAX_BLOB_WIDTH; }; + bool fix_length_and_dec() + { maybe_null= 1; max_length= MAX_BLOB_WIDTH; return FALSE; }; const char *func_name() const{ return "column_list"; } String *val_str(String *); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_dyncol_list>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_dyncol_list>(thd, this); } }; -#endif /* ITEM_STRFUNC_INCLUDED */ +/* + this is used by JOIN_TAB::keep_current_rowid + and stores handler::position(). + It has nothing to do with _rowid pseudo-column, that the parser supports. +*/ +class Item_temptable_rowid :public Item_str_func +{ +public: + TABLE *table; + Item_temptable_rowid(TABLE *table_arg); + const Type_handler *type_handler() const { return &type_handler_string; } + Field *create_tmp_field(bool group, TABLE *table) + { return create_table_field_from_handler(table); } + String *val_str(String *str); + enum Functype functype() const { return TEMPTABLE_ROWID; } + const char *func_name() const { return "<rowid>"; } - void fix_length_and_dec(); ++ bool fix_length_and_dec(); + Item *get_copy(THD *thd) + { return get_item_copy<Item_temptable_rowid>(thd, this); } +}; +#endif /* ITEM_STRFUNC_INCLUDED */ diff --cc sql/item_subselect.cc index 4280a67e356,8a9dd083911..1947a45186a --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@@ -1181,12 -1182,26 +1187,12 @@@ void Item_singlerow_subselect::store(ui row[i]->cache_value(); } -enum Item_result Item_singlerow_subselect::result_type() const -{ - return engine->type(); -} - -enum Item_result Item_singlerow_subselect::cmp_type() const -{ - return engine->cmptype(); -} - -/* - Don't rely on the result type to calculate field type. - Ask the engine instead. -*/ -enum_field_types Item_singlerow_subselect::field_type() const +const Type_handler *Item_singlerow_subselect::type_handler() const { - return engine->field_type(); + return engine->type_handler(); } - void Item_singlerow_subselect::fix_length_and_dec() + bool Item_singlerow_subselect::fix_length_and_dec() { if ((max_columns= engine->cols()) == 1) { @@@ -3721,19 -3742,21 +3732,21 @@@ bool subselect_engine::set_row(List<Ite item->decimals= sel_item->decimals; item->unsigned_flag= sel_item->unsigned_flag; maybe_null= sel_item->maybe_null; - if (!(row[i]= Item_cache::get_cache(thd, sel_item, sel_item->cmp_type()))) + if (!(row[i]= sel_item->get_cache(thd))) - return; + return TRUE; row[i]->setup(thd, sel_item); //psergey-backport-timours: row[i]->store(sel_item); } if (item_list.elements > 1) - cmp_type= res_type= ROW_RESULT; + set_handler(&type_handler_row); + return FALSE; } - void subselect_single_select_engine::fix_length_and_dec(Item_cache **row) + bool subselect_single_select_engine::fix_length_and_dec(Item_cache **row) { DBUG_ASSERT(row || select_lex->item_list.elements==1); - set_row(select_lex->item_list, row); + if (set_row(select_lex->item_list, row)) + return TRUE; item->collation.set(row[0]->collation); if (cols() != 1) maybe_null= 0; diff --cc sql/item_subselect.h index dfe3287615b,bd6a1bdc498..363dbba4ddd --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@@ -305,10 -303,12 +305,10 @@@ public my_decimal *val_decimal(my_decimal *); bool val_bool(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); - enum Item_result result_type() const; - enum Item_result cmp_type() const; - enum_field_types field_type() const; + const Type_handler *type_handler() const; - void fix_length_and_dec(); + bool fix_length_and_dec(); - uint cols(); + uint cols() const; Item* element_index(uint i) { return reinterpret_cast<Item*>(row[i]); } Item** addr(uint i) { return (Item**)row + i; } bool check_cols(uint c); @@@ -401,10 -402,8 +401,10 @@@ public String *val_str(String*); my_decimal *val_decimal(my_decimal *); bool val_bool(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return get_date_from_int(ltime, fuzzydate); } bool fix_fields(THD *thd, Item **ref); - void fix_length_and_dec(); + bool fix_length_and_dec(); void print(String *str, enum_query_type query_type); bool select_transformer(JOIN *join); void top_level_item() { abort_on_null=1; } @@@ -865,9 -870,9 +865,9 @@@ public Item_subselect *item); void cleanup(); int prepare(THD *thd); - void fix_length_and_dec(Item_cache** row); + bool fix_length_and_dec(Item_cache** row); int exec(); - uint cols(); + uint cols() const; uint8 uncacheable(); void exclude(); table_map upper_select_const_tables(); @@@ -901,9 -905,9 +901,9 @@@ public Item_subselect *item); void cleanup(); int prepare(THD *); - void fix_length_and_dec(Item_cache** row); + bool fix_length_and_dec(Item_cache** row); int exec(); - uint cols(); + uint cols() const; uint8 uncacheable(); void exclude(); table_map upper_select_const_tables(); @@@ -959,9 -963,9 +959,9 @@@ public ~subselect_uniquesubquery_engine(); void cleanup(); int prepare(THD *); - void fix_length_and_dec(Item_cache** row); + bool fix_length_and_dec(Item_cache** row); int exec(); - uint cols() { return 1; } + uint cols() const { return 1; } uint8 uncacheable() { return UNCACHEABLE_DEPENDENT_INJECTED; } void exclude(); table_map upper_select_const_tables() { return 0; } @@@ -1381,8 -1385,8 +1381,8 @@@ public uint count_columns_with_nulls_arg); int prepare(THD *thd_arg) { set_thd(thd_arg); return 0; } int exec(); - void fix_length_and_dec(Item_cache**) {} + bool fix_length_and_dec(Item_cache**) { return FALSE; } - uint cols() { /* TODO: what is the correct value? */ return 1; } + uint cols() const { /* TODO: what is the correct value? */ return 1; } uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; } void exclude() {} table_map upper_select_const_tables() { return 0; } diff --cc sql/item_sum.cc index 0e506cc26f2,9e59ec4e373..3163fb9ea2e --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@@ -1167,25 -1161,40 +1166,27 @@@ Item_sum_hybrid::fix_fields(THD *thd, I with_param= args[0]->with_param; with_window_func|= args[0]->with_window_func; - fix_length_and_dec(); - Item *item2= item->real_item(); - if (item2->type() == Item::FIELD_ITEM) - set_handler_by_field_type(((Item_field*) item2)->field->type()); - else if (item->cmp_type() == TIME_RESULT) - set_handler_by_field_type(item2->field_type()); - else - set_handler_by_result_type(item2->result_type(), - max_length, collation.collation); ++ if (fix_length_and_dec()) ++ DBUG_RETURN(TRUE); + - switch (Item_sum_hybrid::result_type()) { - case INT_RESULT: - case DECIMAL_RESULT: - case STRING_RESULT: - break; - case REAL_RESULT: - max_length= float_length(decimals); - break; - case ROW_RESULT: - case TIME_RESULT: - DBUG_ASSERT(0); - }; if (!is_window_func_sum_expr()) setup_hybrid(thd, args[0], NULL); - /* MIN/MAX can return NULL for empty set indepedent of the used column */ - maybe_null= 1; result_field=0; - null_value=1; - if (fix_length_and_dec() || - check_sum_func(thd, ref)) - return TRUE; + + if (check_sum_func(thd, ref)) + DBUG_RETURN(TRUE); orig_args[0]= args[0]; fixed= 1; - return FALSE; + DBUG_RETURN(FALSE); +} + + - void Item_sum_hybrid::fix_length_and_dec() ++bool Item_sum_hybrid::fix_length_and_dec() +{ + DBUG_ASSERT(args[0]->field_type() == args[0]->real_item()->field_type()); + DBUG_ASSERT(args[0]->result_type() == args[0]->real_item()->result_type()); - (void) args[0]->type_handler()->Item_sum_hybrid_fix_length_and_dec(this); ++ return args[0]->type_handler()->Item_sum_hybrid_fix_length_and_dec(this); } @@@ -1235,181 -1244,42 +1236,182 @@@ Field *Item_sum_hybrid::create_tmp_fiel if (args[0]->type() == Item::FIELD_ITEM) { - field= ((Item_field*) args[0])->field; - - if ((field= create_tmp_field_from_field(table->in_use, field, name, table, - NULL))) + Field *field= ((Item_field*) args[0])->field; + if ((field= create_tmp_field_from_field(table->in_use, field, &name, + table, NULL))) field->flags&= ~NOT_NULL_FLAG; - return field; + DBUG_RETURN(field); } + DBUG_RETURN(tmp_table_field_from_field_type(table)); +} - /* - DATE/TIME fields have STRING_RESULT result types. - In order to preserve field type, it's needed to handle DATE/TIME - fields creations separately. - */ - mem_root= table->in_use->mem_root; - switch (args[0]->field_type()) { - case MYSQL_TYPE_DATE: - field= new (mem_root) - Field_newdate(0, maybe_null ? (uchar*)"" : 0, 0, Field::NONE, name); - break; - case MYSQL_TYPE_TIME: - field= new_Field_time(mem_root, 0, maybe_null ? (uchar*)"" : 0, 0, - Field::NONE, name, decimals); - break; - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: - field= new_Field_datetime(mem_root, 0, maybe_null ? (uchar*)"" : 0, 0, - Field::NONE, name, decimals); - break; - default: - return Item_sum::create_tmp_field(group, table); +/*********************************************************************** +** Item_sum_sp class +***********************************************************************/ + +Item_sum_sp::Item_sum_sp(THD *thd, Name_resolution_context *context_arg, + sp_name *name_arg, sp_head *sp, List<Item> &list) + :Item_sum(thd, list), Item_sp(thd, context_arg, name_arg) +{ + maybe_null= 1; + quick_group= 0; + m_sp= sp; +} + +Item_sum_sp::Item_sum_sp(THD *thd, Name_resolution_context *context_arg, + sp_name *name_arg, sp_head *sp) + :Item_sum(thd), Item_sp(thd, context_arg, name_arg) +{ + maybe_null= 1; + quick_group= 0; + m_sp= sp; +} + +Item_sum_sp::Item_sum_sp(THD *thd, Item_sum_sp *item): + Item_sum(thd, item), Item_sp(thd, item) +{ + maybe_null= item->maybe_null; + quick_group= item->quick_group; +} + +bool +Item_sum_sp::fix_fields(THD *thd, Item **ref) +{ + DBUG_ASSERT(fixed == 0); + if (init_sum_func_check(thd)) + return TRUE; + decimals= 0; + + m_sp= m_sp ? m_sp : sp_handler_function.sp_find_routine(thd, m_name, true); + + if (!m_sp) + { + my_missing_function_error(m_name->m_name, ErrConvDQName(m_name).ptr()); + context->process_error(thd); + return TRUE; } - if (field) - field->init(table); - return field; + + if (init_result_field(thd, max_length, maybe_null, &null_value, &name)) + return TRUE; + + for (uint i= 0 ; i < arg_count ; i++) + { + if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i])) + return TRUE; + set_if_bigger(decimals, args[i]->decimals); + m_with_subquery|= args[i]->with_subquery(); + with_window_func|= args[i]->with_window_func; + } + result_field= NULL; + max_length= float_length(decimals); + null_value= 1; - fix_length_and_dec(); ++ if (fix_length_and_dec()) ++ return TRUE; + + if (check_sum_func(thd, ref)) + return TRUE; + + memcpy(orig_args, args, sizeof(Item *) * arg_count); + fixed= 1; + return FALSE; +} + +/** + Execute function to store value in result field. + This is called when we need the value to be returned for the function. + Here we send a signal in form of the server status that all rows have been + fetched and now we have to exit from the function with the return value. + @return Function returns error status. + @retval FALSE on success. + @retval TRUE if an error occurred. +*/ + +bool +Item_sum_sp::execute() +{ + THD *thd= current_thd; + bool res; + uint old_server_status= thd->server_status; + + /* We set server status so we can send a signal to exit from the + function with the return value. */ + + thd->server_status= SERVER_STATUS_LAST_ROW_SENT; + res= Item_sp::execute(thd, &null_value, args, arg_count); + thd->server_status= old_server_status; + return res; +} + +/** + Handles the aggregation of the values. + @note: See class description for more details on how and why this is done. + @return The error state. + @retval FALSE on success. + @retval TRUE if an error occurred. +*/ + +bool +Item_sum_sp::add() +{ + return execute_impl(current_thd, args, arg_count); +} + + +void +Item_sum_sp::clear() +{ + delete func_ctx; + func_ctx= NULL; + sp_query_arena->free_items(); + free_root(&sp_mem_root, MYF(0)); +} + +const Type_handler *Item_sum_sp::type_handler() const +{ + DBUG_ENTER("Item_sum_sp::type_handler"); + DBUG_PRINT("info", ("m_sp = %p", (void *) m_sp)); + DBUG_ASSERT(sp_result_field); + // This converts ENUM/SET to STRING + const Type_handler *handler= sp_result_field->type_handler(); + DBUG_RETURN(handler->type_handler_for_item_field()); +} + +void +Item_sum_sp::cleanup() +{ + Item_sp::cleanup(); + Item_sum::cleanup(); } +/** + Initialize local members with values from the Field interface. + @note called from Item::fix_fields. +*/ + - void ++bool +Item_sum_sp::fix_length_and_dec() +{ + DBUG_ENTER("Item_sum_sp::fix_length_and_dec"); + DBUG_ASSERT(sp_result_field); + Type_std_attributes::set(sp_result_field->type_std_attributes()); - Item_sum::fix_length_and_dec(); - DBUG_VOID_RETURN; ++ bool res= Item_sum::fix_length_and_dec(); ++ DBUG_RETURN(res); +} + +const char * +Item_sum_sp::func_name() const +{ + THD *thd= current_thd; + return Item_sp::func_name(thd); +} + +Item* Item_sum_sp::copy_or_same(THD *thd) +{ + Item_sum_sp *copy_item= new (thd->mem_root) Item_sum_sp(thd, this); + copy_item->init_result_field(thd, max_length, maybe_null, + ©_item->null_value, ©_item->name); + return copy_item; +} /*********************************************************************** ** reset and add of sum_func @@@ -1467,68 -1327,42 +1469,70 @@@ void Item_sum_sum::clear( } +void Item_sum_sum::fix_length_and_dec_double() +{ + set_handler(&type_handler_double); // Change FLOAT to DOUBLE + decimals= args[0]->decimals; + sum= 0.0; +} + + +void Item_sum_sum::fix_length_and_dec_decimal() +{ + set_handler(&type_handler_newdecimal); // Change temporal to new DECIMAL + decimals= args[0]->decimals; + /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */ + int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS; + max_length= my_decimal_precision_to_length_no_truncation(precision, + decimals, + unsigned_flag); + curr_dec_buff= 0; + my_decimal_set_zero(dec_buffs); +} + + - void Item_sum_sum::fix_length_and_dec() + bool Item_sum_sum::fix_length_and_dec() { DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); maybe_null=null_value=1; - args[0]->cast_to_int_type_handler()->Item_sum_sum_fix_length_and_dec(this); - decimals= args[0]->decimals; - switch (args[0]->cast_to_int_type()) { - case REAL_RESULT: - case STRING_RESULT: - set_handler_by_field_type(MYSQL_TYPE_DOUBLE); - sum= 0.0; - break; - case INT_RESULT: - case TIME_RESULT: - case DECIMAL_RESULT: ++ if (args[0]->cast_to_int_type_handler()-> ++ Item_sum_sum_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); + DBUG_PRINT("info", ("Type: %s (%d, %d)", type_handler()->name().ptr(), + max_length, (int) decimals)); - DBUG_VOID_RETURN; ++ DBUG_RETURN(FALSE); +} + + +void Item_sum_sum::direct_add(my_decimal *add_sum_decimal) +{ + DBUG_ENTER("Item_sum_sum::direct_add"); + DBUG_PRINT("info", ("add_sum_decimal: %p", add_sum_decimal)); + direct_added= TRUE; + direct_reseted_field= FALSE; + if (add_sum_decimal) { - /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */ - int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS; - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - curr_dec_buff= 0; - set_handler_by_field_type(MYSQL_TYPE_NEWDECIMAL); - my_decimal_set_zero(dec_buffs); - break; + direct_sum_is_null= FALSE; + direct_sum_decimal= *add_sum_decimal; } - case ROW_RESULT: - DBUG_ASSERT(0); + else + { + direct_sum_is_null= TRUE; + direct_sum_decimal= decimal_zero; } - DBUG_PRINT("info", ("Type: %s (%d, %d)", - (result_type() == REAL_RESULT ? "REAL_RESULT" : - result_type() == DECIMAL_RESULT ? "DECIMAL_RESULT" : - result_type() == INT_RESULT ? "INT_RESULT" : - "--ILLEGAL!!!--"), - max_length, - (int)decimals)); - DBUG_RETURN(FALSE); + DBUG_VOID_RETURN; +} + + +void Item_sum_sum::direct_add(double add_sum_real, bool add_sum_is_null) +{ + DBUG_ENTER("Item_sum_sum::direct_add"); + DBUG_PRINT("info", ("add_sum_real: %f", add_sum_real)); + direct_added= TRUE; + direct_reseted_field= FALSE; + direct_sum_is_null= add_sum_is_null; + direct_sum_real= add_sum_real; + DBUG_VOID_RETURN; } @@@ -1889,39 -1662,30 +1893,41 @@@ void Item_sum_count::cleanup( /* Avgerage */ + +void Item_sum_avg::fix_length_and_dec_decimal() +{ + Item_sum_sum::fix_length_and_dec_decimal(); + int precision= args[0]->decimal_precision() + prec_increment; + decimals= MY_MIN(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE); + max_length= my_decimal_precision_to_length_no_truncation(precision, + decimals, + unsigned_flag); + f_precision= MY_MIN(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION); + f_scale= args[0]->decimals; + dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale); +} + + +void Item_sum_avg::fix_length_and_dec_double() +{ + Item_sum_sum::fix_length_and_dec_double(); + decimals= MY_MIN(args[0]->decimals + prec_increment, + FLOATING_POINT_DECIMALS); + max_length= MY_MIN(args[0]->max_length + prec_increment, float_length(decimals)); +} + + - void Item_sum_avg::fix_length_and_dec() + bool Item_sum_avg::fix_length_and_dec() { - if (Item_sum_sum::fix_length_and_dec()) - return TRUE; - maybe_null=null_value=1; + DBUG_ENTER("Item_sum_avg::fix_length_and_dec"); prec_increment= current_thd->variables.div_precincrement; - if (Item_sum_avg::result_type() == DECIMAL_RESULT) - { - int precision= args[0]->decimal_precision() + prec_increment; - decimals= MY_MIN(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE); - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - f_precision= MY_MIN(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION); - f_scale= args[0]->decimals; - dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale); - } - else - { - decimals= MY_MIN(args[0]->decimals + prec_increment, - FLOATING_POINT_DECIMALS); - max_length= MY_MIN(args[0]->max_length + prec_increment, float_length(decimals)); - } - return FALSE; + maybe_null=null_value=1; - args[0]->cast_to_int_type_handler()->Item_sum_avg_fix_length_and_dec(this); ++ if (args[0]->cast_to_int_type_handler()-> ++ Item_sum_avg_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); + DBUG_PRINT("info", ("Type: %s (%d, %d)", type_handler()->name().ptr(), + max_length, (int) decimals)); - DBUG_VOID_RETURN; ++ DBUG_RETURN(FALSE); } @@@ -2114,26 -1884,7 +2120,26 @@@ Item_sum_variance::Item_sum_variance(TH } +void Item_sum_variance::fix_length_and_dec_double() +{ + DBUG_ASSERT(Item_sum_variance::type_handler() == &type_handler_double); + decimals= MY_MIN(args[0]->decimals + 4, FLOATING_POINT_DECIMALS); +} + + +void Item_sum_variance::fix_length_and_dec_decimal() +{ + DBUG_ASSERT(Item_sum_variance::type_handler() == &type_handler_double); + int precision= args[0]->decimal_precision() * 2 + prec_increment; + decimals= MY_MIN(args[0]->decimals + prec_increment, + FLOATING_POINT_DECIMALS - 1); + max_length= my_decimal_precision_to_length_no_truncation(precision, + decimals, + unsigned_flag); +} + + - void Item_sum_variance::fix_length_and_dec() + bool Item_sum_variance::fix_length_and_dec() { DBUG_ENTER("Item_sum_variance::fix_length_and_dec"); maybe_null= null_value= 1; @@@ -2145,11 -1896,30 +2151,11 @@@ type of the result is an implementation-defined aproximate numeric type. */ -- - args[0]->type_handler()->Item_sum_variance_fix_length_and_dec(this); - switch (args[0]->result_type()) { - case REAL_RESULT: - case STRING_RESULT: - decimals= MY_MIN(args[0]->decimals + 4, FLOATING_POINT_DECIMALS); - break; - case INT_RESULT: - case DECIMAL_RESULT: - { - int precision= args[0]->decimal_precision()*2 + prec_increment; - decimals= MY_MIN(args[0]->decimals + prec_increment, - FLOATING_POINT_DECIMALS-1); - max_length= my_decimal_precision_to_length_no_truncation(precision, - decimals, - unsigned_flag); - - break; - } - case ROW_RESULT: - case TIME_RESULT: - DBUG_ASSERT(0); - } - DBUG_PRINT("info", ("Type: REAL_RESULT (%d, %d)", max_length, (int)decimals)); ++ if (args[0]->type_handler()->Item_sum_variance_fix_length_and_dec(this)) ++ DBUG_RETURN(TRUE); + DBUG_PRINT("info", ("Type: %s (%d, %d)", type_handler()->name().ptr(), + max_length, (int)decimals)); - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } diff --cc sql/item_sum.h index b66f6ab6143,5c8ff520259..b400ebd5f80 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@@ -457,7 -456,9 +457,8 @@@ public Updated value is then saved in the field. */ virtual void update_field()=0; - virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - virtual bool keep_field_type(void) const { return 0; } + virtual bool fix_length_and_dec() + { maybe_null=1; null_value=1; return FALSE; } virtual Item *result_item(THD *thd, Field *field); void update_used_tables (); @@@ -752,9 -751,10 +753,9 @@@ public double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); my_decimal *val_decimal(my_decimal *); - enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + const Type_handler *type_handler() const { return &type_handler_longlong; } - void fix_length_and_dec() - { decimals=0; max_length=21; maybe_null=null_value=0; } + bool fix_length_and_dec() + { decimals=0; max_length=21; maybe_null=null_value=0; return FALSE; } }; @@@ -762,15 -762,10 +763,15 @@@ class Item_sum_sum :public Item_sum_num public Type_handler_hybrid_field_type { protected: + bool direct_added; + bool direct_reseted_field; + bool direct_sum_is_null; + double direct_sum_real; double sum; + my_decimal direct_sum_decimal; my_decimal dec_buffs[2]; uint curr_dec_buff; - void fix_length_and_dec(); + bool fix_length_and_dec(); public: Item_sum_sum(THD *thd, Item *item_par, bool distinct): @@@ -903,9 -889,7 +904,9 @@@ public :Item_sum_sum(thd, item), count(item->count), prec_increment(item->prec_increment) {} + void fix_length_and_dec_double(); + void fix_length_and_dec_decimal(); - void fix_length_and_dec(); + bool fix_length_and_dec(); enum Sumfunctype sum_func () const { return has_with_distinct() ? AVG_DISTINCT_FUNC : AVG_FUNC; @@@ -1052,10 -1033,8 +1053,10 @@@ protected cmp_sign(item->cmp_sign), was_values(item->was_values) { } bool fix_fields(THD *, Item **); - void fix_length_and_dec(); ++ bool fix_length_and_dec(); void setup_hybrid(THD *thd, Item *item, Item *value_arg); void clear(); + void direct_add(Item *item); double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); @@@ -1228,142 -1210,6 +1232,142 @@@ private void set_bits_from_counters(); }; +class sp_head; +class sp_name; +class Query_arena; +struct st_sp_security_context; + +/* + Item_sum_sp handles STORED AGGREGATE FUNCTIONS + + Each Item_sum_sp represents a custom aggregate function. Inside the + function's body, we require at least one occurence of FETCH GROUP NEXT ROW + instruction. This cursor is what makes custom stored aggregates possible. + + During computation the function's add method is called. This in turn performs + an execution of the function. The function will execute from the current + function context (and instruction), if one exists, or from the start if not. + See Item_sp for more details. + + Upon encounter of FETCH GROUP NEXT ROW instruction, the function will pause + execution. We assume that the user has performed the necessary additions for + a row, between two encounters of FETCH GROUP NEXT ROW. + + Example: + create aggregate function f1(x INT) returns int + begin + declare continue handler for not found return s; + declare s int default 0 + loop + fetch group next row; + set s = s + x; + end loop; + end + + The function will always stop after an encounter of FETCH GROUP NEXT ROW, + except (!) on first encounter, as the value for the first row in the + group is already set in the argument x. This behaviour is done so when + a user writes a function, he should "logically" include FETCH GROUP NEXT ROW + before any "add" instructions in the stored function. This means however that + internally, the first occurence doesn't stop the function. See the + implementation of FETCH GROUP NEXT ROW for details as to how it happens. + + Either way, one should assume that after calling "Item_sum_sp::add()" that + the values for that particular row have been added to the aggregation. + + To produce values for val_xxx methods we need an extra syntactic construct. + We require a continue handler when "no more rows are available". val_xxx + methods force a function return by executing the function again, while + setting a server flag that no more rows have been found. This implies + that val_xxx methods should only be called once per group however. + + Example: + DECLARE CONTINUE HANDLER FOR NOT FOUND RETURN ret_val; +*/ +class Item_sum_sp :public Item_sum, + public Item_sp +{ + private: + bool execute(); + +public: + Item_sum_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, + sp_head *sp); + + Item_sum_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name, + sp_head *sp, List<Item> &list); + Item_sum_sp(THD *thd, Item_sum_sp *item); + + enum Sumfunctype sum_func () const + { + return SP_AGGREGATE_FUNC; + } + Field *create_field_for_create_select(TABLE *table) + { + return create_table_field_from_handler(table); + } - void fix_length_and_dec(); ++ bool fix_length_and_dec(); + bool fix_fields(THD *thd, Item **ref); + const char *func_name() const; + const Type_handler *type_handler() const; + bool add(); + + /* val_xx functions */ + longlong val_int() + { + if(execute()) + return 0; + return sp_result_field->val_int(); + } + + double val_real() + { + if(execute()) + return 0.0; + return sp_result_field->val_real(); + } + + my_decimal *val_decimal(my_decimal *dec_buf) + { + if(execute()) + return NULL; + return sp_result_field->val_decimal(dec_buf); + } + + String *val_str(String *str) + { + String buf; + char buff[20]; + buf.set(buff, 20, str->charset()); + buf.length(0); + if (execute()) + return NULL; + /* + result_field will set buf pointing to internal buffer + of the resul_field. Due to this it will change any time + when SP is executed. In order to prevent occasional + corruption of returned value, we make here a copy. + */ + sp_result_field->val_str(&buf); + str->copy(buf); + return str; + } + void reset_field(){DBUG_ASSERT(0);} + void update_field(){DBUG_ASSERT(0);} + void clear(); + void cleanup(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return execute() || sp_result_field->get_date(ltime, fuzzydate); + } + inline Field *get_sp_result_field() + { + return sp_result_field; + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_sp>(thd, this); } + Item *copy_or_same(THD *thd); +}; /* Items to get the value of a stored sum function */ @@@ -1561,11 -1402,13 +1565,11 @@@ class Item_sum_udf_float :public Item_u double val_real(); String *val_str(String*str); my_decimal *val_decimal(my_decimal *); - enum Item_result result_type () const { return REAL_RESULT; } - enum Item_result cmp_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + const Type_handler *type_handler() const { return &type_handler_double; } - void fix_length_and_dec() { fix_num_length_and_dec(); } + bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; } Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_udf_float>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_udf_float>(thd, this); } }; @@@ -1583,11 -1426,12 +1587,11 @@@ public { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); } String *val_str(String*str); my_decimal *val_decimal(my_decimal *); - enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + const Type_handler *type_handler() const { return &type_handler_longlong; } - void fix_length_and_dec() { decimals=0; max_length=21; } + bool fix_length_and_dec() { decimals=0; max_length=21; return FALSE; } Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_udf_int>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_udf_int>(thd, this); } }; @@@ -1624,11 -1468,12 +1628,11 @@@ public return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used); } my_decimal *val_decimal(my_decimal *dec); - enum Item_result result_type () const { return STRING_RESULT; } - enum_field_types field_type() const { return string_field_type(); } + const Type_handler *type_handler() const { return string_type_handler(); } - void fix_length_and_dec(); + bool fix_length_and_dec(); Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_udf_str>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_udf_str>(thd, this); } }; @@@ -1645,11 -1490,12 +1649,11 @@@ public double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); - enum Item_result result_type () const { return DECIMAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + const Type_handler *type_handler() const { return &type_handler_newdecimal; } - void fix_length_and_dec() { fix_num_length_and_dec(); } + bool fix_length_and_dec() { fix_num_length_and_dec(); return FALSE; } Item *copy_or_same(THD* thd); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_udf_decimal>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_udf_decimal>(thd, this); } }; #else /* Dummy functions to get sql_yacc.cc compiled */ @@@ -1720,7 -1566,8 +1724,7 @@@ public { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed == 1); null_value=1; return 0.0; } longlong val_int() { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } - void fix_length_and_dec() { maybe_null=1; max_length=0; } - enum Item_result result_type () const { return STRING_RESULT; } + bool fix_length_and_dec() { maybe_null=1; max_length=0; return FALSE; } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } void clear() {} bool add() { return 0; } diff --cc sql/item_timefunc.cc index e01114fb0ad,bb75ad7c28c..b4d929e0f70 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@@ -1842,17 -1876,10 +1844,17 @@@ overflow return 0; } - void Item_func_date_format::fix_length_and_dec() + bool Item_func_date_format::fix_length_and_dec() { THD* thd= current_thd; - locale= thd->variables.lc_time_names; + if (!is_time_format) + { + if (arg_count < 3) + locale= thd->variables.lc_time_names; + else + if (args[2]->basic_const_item()) + locale= args[2]->locale_from_val_str(); + } /* Must use this_item() in case it's a local SP variable @@@ -2039,8 -2059,8 +2042,9 @@@ bool Item_func_from_unixtime::fix_lengt THD *thd= current_thd; thd->time_zone_used= 1; tz= thd->variables.time_zone; - decimals= args[0]->decimals; - return Item_temporal_func::fix_length_and_dec(); + fix_attributes_datetime_not_fixed_dec(args[0]->decimals); + maybe_null= true; ++ return FALSE; } @@@ -2116,13 -2143,6 +2120,13 @@@ bool Item_date_add_interval::fix_length { enum_field_types arg0_field_type; + if (!args[0]->type_handler()->is_traditional_type()) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), + args[0]->type_handler()->name().ptr(), + "interval", func_name()); - return; ++ return TRUE; + } /* The field type for the result of an Item_datefunc is defined as follows: @@@ -2169,26 -2186,15 +2173,27 @@@ } else if (arg0_field_type == MYSQL_TYPE_TIME) { - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), interval_dec); + uint dec= MY_MAX(args[0]->time_precision(), interval_dec); if (int_type >= INTERVAL_DAY && int_type != INTERVAL_YEAR_MONTH) - set_handler_by_field_type(arg0_field_type); + { + set_handler(&type_handler_time2); + fix_attributes_time(dec); + } else - set_handler_by_field_type(MYSQL_TYPE_DATETIME); + { + set_handler(&type_handler_datetime2); + fix_attributes_datetime(dec); + } } else - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_DATETIME), interval_dec); - return Item_temporal_func::fix_length_and_dec(); + { + uint dec= MY_MAX(args[0]->datetime_precision(), interval_dec); + set_handler(&type_handler_string); + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + } + maybe_null= true; ++ return FALSE; } @@@ -2688,18 -2688,11 +2694,18 @@@ err } - void Item_func_add_time::fix_length_and_dec() + bool Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; - decimals= MY_MAX(args[0]->decimals, args[1]->decimals); + if (!args[0]->type_handler()->is_traditional_type() || + !args[1]->type_handler()->is_traditional_type()) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), + args[0]->type_handler()->name().ptr(), + args[1]->type_handler()->name().ptr(), func_name()); - return; ++ return TRUE; + } /* The field type for the result of an Item_func_add_time function is defined as follows: @@@ -2722,18 -2716,11 +2728,19 @@@ } else if (arg0_field_type == MYSQL_TYPE_TIME) { - set_handler_by_field_type(MYSQL_TYPE_TIME); - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), - args[1]->temporal_precision(MYSQL_TYPE_TIME)); + uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision()); + set_handler(&type_handler_time2); + fix_attributes_time(dec); } - return Item_temporal_func::fix_length_and_dec(); + else + { + uint dec= MY_MAX(args[0]->decimals, args[1]->decimals); + set_handler(&type_handler_string); + collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); + fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec); + } + maybe_null= true; ++ return FALSE; } /** @@@ -3220,25 -3209,21 +3227,25 @@@ get_date_time_result_type(const char *f } - void Item_func_str_to_date::fix_length_and_dec() + bool Item_func_str_to_date::fix_length_and_dec() { + if (!args[0]->type_handler()->is_traditional_type() || + !args[1]->type_handler()->is_traditional_type()) + { + my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0), + args[0]->type_handler()->name().ptr(), + args[1]->type_handler()->name().ptr(), func_name()); - return; ++ return TRUE; + } if (agg_arg_charsets(collation, args, 2, MY_COLL_ALLOW_CONV, 1)) - return; + return TRUE; if (collation.collation->mbminlen > 1) - { -#if MYSQL_VERSION_ID > 50500 internal_charset= &my_charset_utf8mb4_general_ci; -#else - internal_charset= &my_charset_utf8_general_ci; -#endif - } - set_handler_by_field_type(MYSQL_TYPE_DATETIME); - decimals= TIME_SECOND_PART_DIGITS; + maybe_null= true; + set_handler(&type_handler_datetime2); + fix_attributes_datetime(TIME_SECOND_PART_DIGITS); + if ((const_item= args[1]->const_item())) { char format_buff[64]; @@@ -3274,7 -3254,8 +3281,8 @@@ } } } - cached_timestamp_type= mysql_type_to_time_type(field_type()); - return Item_temporal_func::fix_length_and_dec(); + cached_timestamp_type= mysql_timestamp_type(); ++ return FALSE; } diff --cc sql/item_timefunc.h index 30d5018ff36,c983e1a6f8a..51ce3bf2988 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@@ -31,75 -31,63 +31,78 @@@ enum date_time_format_type }; -static inline uint -mysql_temporal_int_part_length(enum enum_field_types mysql_type) +bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval); + + +class Item_long_func_date_field: public Item_long_func { - static uint max_time_type_width[5]= - { MAX_DATETIME_WIDTH, MAX_DATETIME_WIDTH, MAX_DATE_WIDTH, - MAX_DATETIME_WIDTH, MIN_TIME_WIDTH }; - return max_time_type_width[mysql_type_to_time_type(mysql_type)+2]; -} + bool check_arguments() const + { return args[0]->check_type_can_return_date(func_name()); } +public: + Item_long_func_date_field(THD *thd, Item *a) + :Item_long_func(thd, a) { } +}; -bool get_interval_value(Item *args,interval_type int_type, INTERVAL *interval); +class Item_long_func_time_field: public Item_long_func +{ + bool check_arguments() const + { return args[0]->check_type_can_return_time(func_name()); } +public: + Item_long_func_time_field(THD *thd, Item *a) + :Item_long_func(thd, a) { } +}; + -class Item_func_period_add :public Item_int_func +class Item_func_period_add :public Item_long_func { + bool check_arguments() const + { return check_argument_types_can_return_int(0, 2); } public: - Item_func_period_add(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_period_add(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "period_add"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { max_length=6*MY_CHARSET_BIN_MB_MAXLEN; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_period_add>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_period_add>(thd, this); } }; -class Item_func_period_diff :public Item_int_func +class Item_func_period_diff :public Item_long_func { + bool check_arguments() const + { return check_argument_types_can_return_int(0, 2); } public: - Item_func_period_diff(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_period_diff(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "period_diff"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; max_length=6*MY_CHARSET_BIN_MB_MAXLEN; + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_period_diff>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_period_diff>(thd, this); } }; -class Item_func_to_days :public Item_int_func +class Item_func_to_days :public Item_long_func_date_field { public: - Item_func_to_days(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_to_days(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int(); const char *func_name() const { return "to_days"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; max_length=6*MY_CHARSET_BIN_MB_MAXLEN; - maybe_null=1; + maybe_null=1; + return FALSE; } enum_monotonicity_info get_monotonicity_info() const; longlong val_int_endpoint(bool left_endp, bool *incl_endp); @@@ -114,19 -102,18 +117,20 @@@ }; -class Item_func_to_seconds :public Item_int_func +class Item_func_to_seconds :public Item_longlong_func { + bool check_arguments() const + { return check_argument_types_can_return_date(0, arg_count); } public: - Item_func_to_seconds(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_to_seconds(THD *thd, Item *a): Item_longlong_func(thd, a) {} longlong val_int(); const char *func_name() const { return "to_seconds"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; - max_length=6*MY_CHARSET_BIN_MB_MAXLEN; + fix_char_length(12); maybe_null= 1; + return FALSE; } enum_monotonicity_info get_monotonicity_info() const; longlong val_int_endpoint(bool left_endp, bool *incl_endp); @@@ -142,17 -129,18 +146,18 @@@ }; -class Item_func_dayofmonth :public Item_int_func +class Item_func_dayofmonth :public Item_long_func_date_field { public: - Item_func_dayofmonth(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_dayofmonth(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int(); const char *func_name() const { return "dayofmonth"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; - maybe_null=1; + maybe_null=1; + return FALSE; } bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;} @@@ -181,14 -169,11 +186,14 @@@ public str->set(nr, collation.collation); return str; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return get_date_from_int(ltime, fuzzydate); + } const char *func_name() const { return "month"; } - enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + const Type_handler *type_handler() const { return &type_handler_long; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals= 0; fix_char_length(2); maybe_null=1; @@@ -226,14 -212,14 +232,14 @@@ public }; -class Item_func_dayofyear :public Item_int_func +class Item_func_dayofyear :public Item_long_func_date_field { public: - Item_func_dayofyear(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_dayofyear(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int(); const char *func_name() const { return "dayofyear"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals= 0; fix_char_length(3); maybe_null=1; @@@ -249,13 -236,13 +256,13 @@@ }; -class Item_func_hour :public Item_int_func +class Item_func_hour :public Item_long_func_time_field { public: - Item_func_hour(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_hour(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int(); const char *func_name() const { return "hour"; } - void fix_length_and_dec() + bool fix_length_and_dec() { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; @@@ -272,13 -260,13 +280,13 @@@ }; -class Item_func_minute :public Item_int_func +class Item_func_minute :public Item_long_func_time_field { public: - Item_func_minute(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_minute(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int(); const char *func_name() const { return "minute"; } - void fix_length_and_dec() + bool fix_length_and_dec() { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; @@@ -295,14 -284,14 +304,14 @@@ }; -class Item_func_quarter :public Item_int_func +class Item_func_quarter :public Item_long_func_date_field { public: - Item_func_quarter(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_quarter(THD *thd, Item *a): Item_long_func_date_field(thd, a) {} longlong val_int(); const char *func_name() const { return "quarter"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; max_length=1*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; @@@ -318,14 -308,14 +328,14 @@@ }; -class Item_func_second :public Item_int_func +class Item_func_second :public Item_long_func_time_field { public: - Item_func_second(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_second(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int(); const char *func_name() const { return "second"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; @@@ -341,20 -332,15 +352,20 @@@ }; -class Item_func_week :public Item_int_func +class Item_func_week :public Item_long_func { + bool check_arguments() const + { + return args[0]->check_type_can_return_date(func_name()) || + (arg_count > 1 && args[1]->check_type_can_return_int(func_name())); + } public: - Item_func_week(THD *thd, Item *a): Item_int_func(thd, a) {} - Item_func_week(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_week(THD *thd, Item *a): Item_long_func(thd, a) {} + Item_func_week(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "week"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; @@@ -369,24 -356,18 +381,24 @@@ { return arg_count == 2; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_week>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_week>(thd, this); } }; -class Item_func_yearweek :public Item_int_func +class Item_func_yearweek :public Item_long_func { + bool check_arguments() const + { + return args[0]->check_type_can_return_date(func_name()) || + args[1]->check_type_can_return_int(func_name()); + } public: - Item_func_yearweek(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_func_yearweek(THD *thd, Item *a, Item *b) + :Item_long_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "yearweek"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; max_length=6*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; @@@ -445,12 -428,9 +459,12 @@@ public { return (odbc_type ? "dayofweek" : "weekday"); } - enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + return type_handler()->Item_get_date(this, ltime, fuzzydate); + } + const Type_handler *type_handler() const { return &type_handler_long; } - void fix_length_and_dec() + bool fix_length_and_dec() { decimals= 0; fix_char_length(1); @@@ -473,8 -454,9 +488,8 @@@ class Item_func_dayname :public Item_fu Item_func_dayname(THD *thd, Item *a): Item_func_weekday(thd, a, 0) {} const char *func_name() const { return "dayname"; } String *val_str(String *str); - enum Item_result result_type () const { return STRING_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } + const Type_handler *type_handler() const { return &type_handler_varchar; } - void fix_length_and_dec(); + bool fix_length_and_dec(); bool check_partition_func_processor(void *int_arg) {return TRUE;} bool check_vcol_func_processor(void *arg) { @@@ -535,14 -516,10 +550,15 @@@ public return FALSE; return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC); } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - fix_length_and_dec_generic(arg_count ? args[0]->datetime_precision() : 0); ++ fix_length_and_dec_generic(arg_count ? args[0]->datetime_precision() : 0); ++ return FALSE; + } longlong int_op(); my_decimal *decimal_op(my_decimal* buf); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_unix_timestamp>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_unix_timestamp>(thd, this); } }; @@@ -558,14 -537,10 +574,15 @@@ public { return !has_time_args(); } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + fix_length_and_dec_generic(args[0]->time_precision()); ++ return FALSE; + } longlong int_op(); my_decimal *decimal_op(my_decimal* buf); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_time_to_sec>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_time_to_sec>(thd, this); } }; @@@ -627,13 -630,7 +644,14 @@@ class Item_datefunc :public Item_tempor public: Item_datefunc(THD *thd): Item_temporal_func(thd) { } Item_datefunc(THD *thd, Item *a): Item_temporal_func(thd, a) { } - enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + Item_datefunc(THD *thd, Item *a, Item *b): Item_temporal_func(thd, a, b) { } + const Type_handler *type_handler() const { return &type_handler_newdate; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + fix_attributes_date(); + maybe_null= (arg_count > 0); ++ return FALSE; + } }; @@@ -670,7 -667,6 +688,7 @@@ public Item_func_curtime(THD *thd, uint dec): Item_timefunc(thd), last_query_id(0) { decimals= dec; } bool fix_fields(THD *, Item **); - void fix_length_and_dec() { fix_attributes_time(decimals); } ++ bool fix_length_and_dec() { fix_attributes_time(decimals); return FALSE; } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); /* Abstract method that defines which time zone is used for conversion. @@@ -757,7 -753,6 +775,8 @@@ public Item_func_now(THD *thd, uint dec): Item_datetimefunc(thd), last_query_id(0) { decimals= dec; } bool fix_fields(THD *, Item **); - void fix_length_and_dec() { fix_attributes_datetime(decimals); } ++ bool fix_length_and_dec() ++ { fix_attributes_datetime(decimals); return FALSE;} bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time)=0; bool check_vcol_func_processor(void *arg) @@@ -847,24 -840,17 +866,24 @@@ public class Item_func_date_format :public Item_str_func { - MY_LOCALE *locale; + bool check_arguments() const + { + return args[0]->check_type_can_return_date(func_name()) || + check_argument_types_can_return_text(1, arg_count); + } + const MY_LOCALE *locale; int fixed_length; - const bool is_time_format; String value; +protected: + bool is_time_format; public: - Item_func_date_format(THD *thd, Item *a, Item *b, bool is_time_format_arg): - Item_str_func(thd, a, b), is_time_format(is_time_format_arg) {} + Item_func_date_format(THD *thd, Item *a, Item *b): + Item_str_func(thd, a, b), locale(0), is_time_format(false) {} + Item_func_date_format(THD *thd, Item *a, Item *b, Item *c): + Item_str_func(thd, a, b, c), locale(0), is_time_format(false) {} String *val_str(String *str); - const char *func_name() const - { return is_time_format ? "time_format" : "date_format"; } + const char *func_name() const { return "date_format"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); uint format_length(const String *format); bool eq(const Item *item, bool binary_cmp) const; bool check_vcol_func_processor(void *arg) @@@ -897,10 -870,10 +916,10 @@@ class Item_func_from_unixtime :public I public: Item_func_from_unixtime(THD *thd, Item *a): Item_datetimefunc(thd, a) {} const char *func_name() const { return "from_unixtime"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_from_unixtime>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_from_unixtime>(thd, this); } }; @@@ -937,15 -905,11 +956,16 @@@ class Item_func_convert_tz :public Item Item_func_convert_tz(THD *thd, Item *a, Item *b, Item *c): Item_datetimefunc(thd, a, b, c), from_tz_cached(0), to_tz_cached(0) {} const char *func_name() const { return "convert_tz"; } - void fix_length_and_dec() - bool fix_length_and_dec(); ++ bool fix_length_and_dec() + { + fix_attributes_datetime(args[0]->datetime_precision()); + maybe_null= true; ++ return FALSE; + } bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); void cleanup(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_convert_tz>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_convert_tz>(thd, this); } }; @@@ -956,14 -918,14 +976,15 @@@ class Item_func_sec_to_time :public Ite public: Item_func_sec_to_time(THD *thd, Item *item): Item_timefunc(thd, item) {} bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); - void fix_length_and_dec() + bool fix_length_and_dec() { - decimals= MY_MIN(args[0]->decimals, TIME_SECOND_PART_DIGITS); - return Item_timefunc::fix_length_and_dec(); + fix_attributes_time(args[0]->decimals); + maybe_null= true; ++ return FALSE; } const char *func_name() const { return "sec_to_time"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_sec_to_time>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_sec_to_time>(thd, this); } }; @@@ -1116,23 -1078,12 +1137,23 @@@ public enum Functype functype() const { return CHAR_TYPECAST_FUNC; } bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "cast_as_char"; } + CHARSET_INFO *cast_charset() const { return cast_cs; } String *val_str(String *a); - bool fix_length_and_dec(); + void fix_length_and_dec_generic(); + void fix_length_and_dec_numeric(); + void fix_length_and_dec_str() + { + fix_length_and_dec_generic(); + m_suppress_warning_to_error_escalation= true; + } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_char_typecast_fix_length_and_dec(this); ++ return args[0]->type_handler()->Item_char_typecast_fix_length_and_dec(this); + } void print(String *str, enum_query_type query_type); bool need_parentheses_in_default() { return true; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_char_typecast>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_char_typecast>(thd, this); } }; @@@ -1151,13 -1108,9 +1172,13 @@@ public const char *func_name() const { return "cast_as_date"; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); const char *cast_type() const { return "date"; } - enum_field_types field_type() const { return MYSQL_TYPE_DATE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_date_typecast>(thd, mem_root, this); } + const Type_handler *type_handler() const { return &type_handler_newdate; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_date_typecast_fix_length_and_dec(this); ++ return args[0]->type_handler()->Item_date_typecast_fix_length_and_dec(this); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_date_typecast>(thd, this); } }; @@@ -1169,13 -1122,9 +1190,14 @@@ public const char *func_name() const { return "cast_as_time"; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); const char *cast_type() const { return "time"; } - enum_field_types field_type() const { return MYSQL_TYPE_TIME; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_time_typecast>(thd, mem_root, this); } + const Type_handler *type_handler() const { return &type_handler_time2; } - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_time_typecast_fix_length_and_dec(this); ++ return args[0]->type_handler()-> ++ Item_time_typecast_fix_length_and_dec(this); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_time_typecast>(thd, this); } }; @@@ -1186,14 -1135,10 +1208,15 @@@ public Item_temporal_typecast(thd, a) { decimals= dec_arg; } const char *func_name() const { return "cast_as_datetime"; } const char *cast_type() const { return "datetime"; } - enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } + const Type_handler *type_handler() const { return &type_handler_datetime2; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); - void fix_length_and_dec() - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_datetime_typecast>(thd, mem_root, this); } ++ bool fix_length_and_dec() + { - args[0]->type_handler()->Item_datetime_typecast_fix_length_and_dec(this); ++ return args[0]->type_handler()-> ++ Item_datetime_typecast_fix_length_and_dec(this); + } + Item *get_copy(THD *thd) + { return get_item_copy<Item_datetime_typecast>(thd, this); } }; @@@ -1235,15 -1177,15 +1258,16 @@@ class Item_func_timediff :public Item_t public: Item_func_timediff(THD *thd, Item *a, Item *b): Item_timefunc(thd, a, b) {} const char *func_name() const { return "timediff"; } - void fix_length_and_dec() + bool fix_length_and_dec() { - decimals= MY_MAX(args[0]->temporal_precision(MYSQL_TYPE_TIME), - args[1]->temporal_precision(MYSQL_TYPE_TIME)); - return Item_timefunc::fix_length_and_dec(); + uint dec= MY_MAX(args[0]->time_precision(), args[1]->time_precision()); + fix_attributes_time(dec); + maybe_null= true; ++ return FALSE; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_timediff>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_timediff>(thd, this); } }; class Item_func_maketime :public Item_timefunc @@@ -1257,10 -1194,10 +1281,11 @@@ public Item_func_maketime(THD *thd, Item *a, Item *b, Item *c): Item_timefunc(thd, a, b, c) {} - void fix_length_and_dec() + bool fix_length_and_dec() { - decimals= MY_MIN(args[2]->decimals, TIME_SECOND_PART_DIGITS); - return Item_timefunc::fix_length_and_dec(); + fix_attributes_time(args[2]->decimals); + maybe_null= true; ++ return FALSE; } const char *func_name() const { return "maketime"; } bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); @@@ -1269,17 -1206,17 +1294,18 @@@ }; -class Item_func_microsecond :public Item_int_func +class Item_func_microsecond :public Item_long_func_time_field { public: - Item_func_microsecond(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_func_microsecond(THD *thd, Item *a): Item_long_func_time_field(thd, a) {} longlong val_int(); const char *func_name() const { return "microsecond"; } - void fix_length_and_dec() - { + bool fix_length_and_dec() + { decimals=0; maybe_null=1; + fix_char_length(6); + return FALSE; } bool check_partition_func_processor(void *int_arg) {return FALSE;} bool check_vcol_func_processor(void *arg) { return FALSE;} @@@ -1299,17 -1234,18 +1325,18 @@@ class Item_func_timestamp_diff :public const interval_type int_type; public: Item_func_timestamp_diff(THD *thd, Item *a, Item *b, interval_type type_arg): - Item_int_func(thd, a, b), int_type(type_arg) {} + Item_longlong_func(thd, a, b), int_type(type_arg) {} const char *func_name() const { return "timestampdiff"; } longlong val_int(); - void fix_length_and_dec() + bool fix_length_and_dec() { decimals=0; maybe_null=1; + return FALSE; } virtual void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_timestamp_diff>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_timestamp_diff>(thd, this); } }; @@@ -1332,10 -1268,11 +1359,11 @@@ public maybe_null= 1; decimals=0; fix_length_and_charset(17, default_charset()); + return FALSE; } virtual void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_get_format>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_get_format>(thd, this); } }; @@@ -1353,9 -1290,9 +1381,9 @@@ public {} bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date); const char *func_name() const { return "str_to_date"; } - void fix_length_and_dec(); + bool fix_length_and_dec(); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_func_str_to_date>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_str_to_date>(thd, this); } }; diff --cc sql/item_vers.h index 17ad3daa73c,00000000000..8b9c0e6056c mode 100644,000000..100644 --- a/sql/item_vers.h +++ b/sql/item_vers.h @@@ -1,114 -1,0 +1,116 @@@ +#ifndef ITEM_VERS_INCLUDED +#define ITEM_VERS_INCLUDED +/* Copyright (c) 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + + +/* System Versioning items */ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +class Item_func_trt_ts: public Item_datetimefunc +{ + TR_table::field_id_t trt_field; +public: + Item_func_trt_ts(THD *thd, Item* a, TR_table::field_id_t _trt_field); + const char *func_name() const + { + if (trt_field == TR_table::FLD_BEGIN_TS) + { + return "trt_begin_ts"; + } + return "trt_commit_ts"; + } + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_trt_ts>(thd, this); } - void fix_length_and_dec() { fix_attributes_datetime(decimals); } ++ bool fix_length_and_dec() ++ { fix_attributes_datetime(decimals); return FALSE; } +}; + +class Item_func_trt_id : public Item_longlong_func +{ + TR_table::field_id_t trt_field; + bool backwards; + + longlong get_by_trx_id(ulonglong trx_id); + longlong get_by_commit_ts(MYSQL_TIME &commit_ts, bool backwards); + +public: + Item_func_trt_id(THD *thd, Item* a, TR_table::field_id_t _trt_field, bool _backwards= false); + Item_func_trt_id(THD *thd, Item* a, Item* b, TR_table::field_id_t _trt_field); + + const char *func_name() const + { + switch (trt_field) + { + case TR_table::FLD_TRX_ID: + return "trt_trx_id"; + case TR_table::FLD_COMMIT_ID: + return "trt_commit_id"; + case TR_table::FLD_ISO_LEVEL: + return "trt_iso_level"; + default: + DBUG_ASSERT(0); + } + return NULL; + } + - void fix_length_and_dec() ++ bool fix_length_and_dec() + { - Item_int_func::fix_length_and_dec(); ++ bool res= Item_int_func::fix_length_and_dec(); + max_length= 20; ++ return res; + } + + longlong val_int(); + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_trt_id>(thd, this); } +}; + +class Item_func_trt_trx_sees : public Item_bool_func +{ +protected: + bool accept_eq; + +public: + Item_func_trt_trx_sees(THD *thd, Item* a, Item* b); + const char *func_name() const + { + return "trt_trx_sees"; + } + longlong val_int(); + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_trt_trx_sees>(thd, this); } +}; + +class Item_func_trt_trx_sees_eq : + public Item_func_trt_trx_sees +{ +public: + Item_func_trt_trx_sees_eq(THD *thd, Item* a, Item* b) : + Item_func_trt_trx_sees(thd, a, b) + { + accept_eq= true; + } + const char *func_name() const + { + return "trt_trx_sees_eq"; + } +}; + +#endif /* ITEM_VERS_INCLUDED */ diff --cc sql/item_windowfunc.h index cb85a2c06d1,e5afb9e1555..48851da7d96 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@@ -524,9 -513,10 +524,9 @@@ class Item_sum_percent_rank: public Ite row_number= 0; } bool add(); - enum Item_result result_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + const Type_handler *type_handler() const { return &type_handler_double; } - void fix_length_and_dec() + bool fix_length_and_dec() { decimals = 10; // TODO-cvicentiu find out how many decimals the standard // requires. @@@ -612,21 -600,18 +613,22 @@@ class Item_sum_cume_dist: public Item_s } void update_field() {} - enum Item_result result_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + const Type_handler *type_handler() const { return &type_handler_double; } - void fix_length_and_dec() + bool fix_length_and_dec() { decimals = 10; // TODO-cvicentiu find out how many decimals the standard // requires. + return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_cume_dist>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_cume_dist>(thd, this); } + + ulonglong get_row_number() + { + return current_row_count_ ; + } private: ulonglong current_row_count_; @@@ -703,277 -689,6 +705,279 @@@ class Item_sum_ntile : public Item_sum_ ulong current_row_count_; }; +class Item_sum_percentile_disc : public Item_sum_cume_dist, + public Type_handler_hybrid_field_type +{ +public: + Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg), + Type_handler_hybrid_field_type(&type_handler_longlong), + value(NULL), val_calculated(FALSE), first_call(TRUE), + prev_value(0), order_item(NULL){} + + double val_real() + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_real(); + } + + longlong val_int() + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_int(); + } + + my_decimal* val_decimal(my_decimal* dec) + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_decimal(dec); + } + + String* val_str(String *str) + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_str(str); + } + + bool add() + { + Item *arg= get_arg(0); + if (arg->is_null()) + return false; + + if (first_call) + { + prev_value= arg->val_real(); + if (prev_value > 1 || prev_value < 0) + { + my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name()); + return true; + } + first_call= false; + } + + double arg_val= arg->val_real(); + + if (prev_value != arg_val) + { + my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name()); + return true; + } + + if (val_calculated) + return false; + + value->store(order_item); + value->cache_value(); + if (value->null_value) + return false; + + Item_sum_cume_dist::add(); + double val= Item_sum_cume_dist::val_real(); + + if (val >= prev_value && !val_calculated) + val_calculated= true; + return false; + } + + enum Sumfunctype sum_func() const + { + return PERCENTILE_DISC_FUNC; + } + + void clear() + { + val_calculated= false; + first_call= true; + value->clear(); + Item_sum_cume_dist::clear(); + } + + const char*func_name() const + { + return "percentile_disc"; + } + + void update_field() {} + void set_type_handler(Window_spec *window_spec); + const Type_handler *type_handler() const + {return Type_handler_hybrid_field_type::type_handler();} + - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + decimals = 10; // TODO-cvicentiu find out how many decimals the standard + // requires. ++ return FALSE; + } + + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_percentile_disc>(thd, this); } + void setup_window_func(THD *thd, Window_spec *window_spec); + void setup_hybrid(THD *thd, Item *item); + bool fix_fields(THD *thd, Item **ref); + +private: + Item_cache *value; + bool val_calculated; + bool first_call; + double prev_value; + Item *order_item; +}; + +class Item_sum_percentile_cont : public Item_sum_cume_dist, + public Type_handler_hybrid_field_type +{ +public: + Item_sum_percentile_cont(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg), + Type_handler_hybrid_field_type(&type_handler_double), + floor_value(NULL), ceil_value(NULL), first_call(TRUE),prev_value(0), + ceil_val_calculated(FALSE), floor_val_calculated(FALSE), order_item(NULL){} + + double val_real() + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + double val= 1 + prev_value * (get_row_count()-1); + + /* + Applying the formula to get the value + If (CRN = FRN = RN) then the result is (value of expression from row at RN) + Otherwise the result is + (CRN - RN) * (value of expression for row at FRN) + + (RN - FRN) * (value of expression for row at CRN) + */ + + if(ceil(val) == floor(val)) + return floor_value->val_real(); + + double ret_val= ((val - floor(val)) * ceil_value->val_real()) + + ((ceil(val) - val) * floor_value->val_real()); + + return ret_val; + } + + bool add() + { + Item *arg= get_arg(0); + if (arg->is_null()) + return false; + + if (first_call) + { + first_call= false; + prev_value= arg->val_real(); + if (prev_value > 1 || prev_value < 0) + { + my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name()); + return true; + } + } + + double arg_val= arg->val_real(); + if (prev_value != arg_val) + { + my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name()); + return true; + } + + if (!floor_val_calculated) + { + floor_value->store(order_item); + floor_value->cache_value(); + if (floor_value->null_value) + return false; + } + if (floor_val_calculated && !ceil_val_calculated) + { + ceil_value->store(order_item); + ceil_value->cache_value(); + if (ceil_value->null_value) + return false; + } + + Item_sum_cume_dist::add(); + double val= 1 + prev_value * (get_row_count()-1); + + if (!floor_val_calculated && get_row_number() == floor(val)) + floor_val_calculated= true; + + if (!ceil_val_calculated && get_row_number() == ceil(val)) + ceil_val_calculated= true; + return false; + } + + enum Sumfunctype sum_func() const + { + return PERCENTILE_CONT_FUNC; + } + + void clear() + { + first_call= true; + floor_value->clear(); + ceil_value->clear(); + floor_val_calculated= false; + ceil_val_calculated= false; + Item_sum_cume_dist::clear(); + } + + const char*func_name() const + { + return "percentile_cont"; + } + void update_field() {} + void set_type_handler(Window_spec *window_spec); + const Type_handler *type_handler() const + {return Type_handler_hybrid_field_type::type_handler();} + - void fix_length_and_dec() ++ bool fix_length_and_dec() + { + decimals = 10; // TODO-cvicentiu find out how many decimals the standard + // requires. ++ return FALSE; + } + + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_percentile_cont>(thd, this); } + void setup_window_func(THD *thd, Window_spec *window_spec); + void setup_hybrid(THD *thd, Item *item); + bool fix_fields(THD *thd, Item **ref); + +private: + Item_cache *floor_value; + Item_cache *ceil_value; + bool first_call; + double prev_value; + bool ceil_val_calculated; + bool floor_val_calculated; + Item *order_item; +}; + + + class Item_window_func : public Item_func_or_sum { diff --cc sql/item_xmlfunc.cc index 63cc07fa34c,738047fea9b..63734ecf9ac --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@@ -456,9 -457,9 +457,9 @@@ public Item_nodeset_func(thd, pxml), string_cache(str_arg) { } String *val_nodeset(String *res) { return string_cache; } - void fix_length_and_dec() { max_length= MAX_BLOB_WIDTH; } - bool fix_length_and_dec() { max_length= MAX_BLOB_WIDTH; return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_nodeset_context_cache>(thd, mem_root, this); } ++ bool fix_length_and_dec() { max_length= MAX_BLOB_WIDTH;; return FALSE; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_nodeset_context_cache>(thd, this); } }; @@@ -468,9 -469,9 +469,9 @@@ class Item_func_xpath_position :public String tmp_value; public: Item_func_xpath_position(THD *thd, Item *a, String *p): - Item_int_func(thd, a), pxml(p) {} + Item_long_func(thd, a), pxml(p) {} const char *func_name() const { return "xpath_position"; } - void fix_length_and_dec() { max_length=10; } + bool fix_length_and_dec() { max_length=10; return FALSE; } longlong val_int() { String *flt= args[0]->val_nodeset(&tmp_value); @@@ -489,9 -490,9 +490,9 @@@ class Item_func_xpath_count :public Ite String tmp_value; public: Item_func_xpath_count(THD *thd, Item *a, String *p): - Item_int_func(thd, a), pxml(p) {} + Item_long_func(thd, a), pxml(p) {} const char *func_name() const { return "xpath_count"; } - void fix_length_and_dec() { max_length=10; } + bool fix_length_and_dec() { max_length=10; return FALSE; } longlong val_int() { uint predicate_supplied_context_size; diff --cc sql/sql_table.cc index 6835d92773c,9a87b0e7461..2b0c4439146 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@@ -4961,9 -4896,14 +4961,14 @@@ int create_table_impl(THD *thd file= mysql_create_frm_image(thd, orig_db, orig_table_name, create_info, alter_info, create_table_mode, key_info, key_count, frm); - if (!file) + /* + TODO: remove this check of thd->is_error() (now it intercept + errors in some val_*() methoids and bring some single place to + such error interception). + */ + if (!file || thd->is_error()) goto err; - if (rea_create_table(thd, frm, path, db, table_name, create_info, + if (rea_create_table(thd, frm, path, db->str, table_name->str, create_info, file, frm_only)) goto err; } @@@ -7621,10 -7401,17 +7626,15 @@@ static bool mysql_inplace_alter_table(T /* Replace the old .FRM with the new .FRM, but keep the old name for now. Rename to the new name (if needed) will be handled separately below. + + TODO: remove this check of thd->is_error() (now it intercept + errors in some val_*() methoids and bring some single place to + such error interception). */ - if (mysql_rename_table(db_type, alter_ctx->new_db, alter_ctx->tmp_name, - alter_ctx->db, alter_ctx->alias, + if (mysql_rename_table(db_type, &alter_ctx->new_db, &alter_ctx->tmp_name, + &alter_ctx->db, &alter_ctx->alias, - FN_FROM_IS_TMP | NO_HA_TABLE)) + FN_FROM_IS_TMP | NO_HA_TABLE) || + thd->is_error()) { // Since changes were done in-place, we can't revert them. (void) quick_rm_table(thd, db_type,