Hello Jerome,
On 01/16/2017 02:45 PM, jerome brauge wrote: > Hello Alexander, > According to your comments, this is the new version. Thanks for addressing my suggestions. We're discussing the change with our architect Sergei Golubchik. Briefly, the idea is: Perhaps we should not change the function CONCAT(). This is a non-standard MySQL/MariaDB function, and it does not exist in Oracle. So probably it should stay sql_mode independent, while sql_mode should affect only the concatenation operator ||. Would this solution work for you? We're still discussing details. I'll get back to you soon. Greetings. > > Best regards, > Jérôme. > > > -----Message d'origine----- > De : Alexander Barkov [mailto:b...@mariadb.org] > Envoyé : vendredi 30 décembre 2016 10:36 > À : jerome brauge > Cc : MariaDB Developers > Objet : Re: MDEV-10142 - bb-10.2-compatibility > > Hello Jerome, > > > On 12/29/2016 08:15 PM, jerome brauge wrote: >> Hello Alexander, >> I built a patch for concat of strings and nulls when sql_mode=oracle. >> Can you review it ? > > Thank you very much for your patch. > It generally looks fine. > I suggest only small changes. > > Please see inline. > >> >> Best regards, >> Jérôme. >> >> > > >> From 6250ce0bcfe563491b25d2e1b4c879f697623537 Mon Sep 17 00:00:00 2001 >> From: jb <jb@JB-PC> >> Date: Mon, 26 Dec 2016 15:03:41 +0100 >> Subject: [PATCH] Adding sql_mode=CONCAT_NULL_YIELDS_NULL_OFF which is >> added by > > I'm not sure about _OFF at the end. It sounds confusing. > > > Perhaps CONCAT_NULL_YIELDS_NOT_NULL would be a better name. > > >> default to sql_mode=ORACLE. Concatenating a zero-length character >> string with another operand always results in the other operand, so >> null can result only from the concatenation of two null strings. >> >> --- >> include/my_bit.h | 5 +++ >> .../suite/compat/oracle/r/func_concat.result | 16 ++++++++ >> mysql-test/suite/compat/oracle/t/func_concat.test | 17 ++++++++ >> scripts/mysql_system_tables.sql | 4 +- >> scripts/mysql_system_tables_fix.sql | 3 +- >> sql/event_db_repository.cc | 2 +- >> sql/item_strfunc.cc | 47 >> +++++++++++++++++----- >> sql/sp.cc | 2 +- >> sql/sql_class.h | 1 + >> sql/sys_vars.cc | 5 ++- >> sql/sys_vars.ic | 8 ++-- >> 11 files changed, 89 insertions(+), 21 deletions(-) create mode >> 100644 mysql-test/suite/compat/oracle/r/func_concat.result >> create mode 100644 mysql-test/suite/compat/oracle/t/func_concat.test >> >> diff --git a/include/my_bit.h b/include/my_bit.h index >> a50403c..4918815 100644 >> --- a/include/my_bit.h >> +++ b/include/my_bit.h >> @@ -130,6 +130,11 @@ static inline uint32 my_set_bits(int n) >> return (((1UL << (n - 1)) - 1) << 1) | 1; } >> >> +static inline uint64 my_set_bits64(int n) { >> + return (((1ULL << (n - 1)) - 1) << 1) | 1; } >> + >> C_MODE_END >> >> #endif /* MY_BIT_INCLUDED */ >> diff --git a/mysql-test/suite/compat/oracle/r/func_concat.result >> b/mysql-test/suite/compat/oracle/r/func_concat.result >> new file mode 100644 >> index 0000000..d055192 >> --- /dev/null >> +++ b/mysql-test/suite/compat/oracle/r/func_concat.result >> @@ -0,0 +1,16 @@ >> +SET sql_mode=ORACLE; >> +SELECT 'a'||'b'; >> +'a'||'b' >> +ab >> +SELECT 'a'||'b'||NULL; >> +'a'||'b'||NULL >> +ab >> +SELECT NULL||'b'||NULL; >> +NULL||'b'||NULL >> +b >> +SELECT NULL||NULL||'c'; >> +NULL||NULL||'c' >> +c >> +SELECT NULL||NULL; >> +NULL||NULL >> +NULL > > > Can you please add tests with table fields? > The implementation of Item_func_concat:val_str() use args[x]->const_item(). > So using non-const arguments would improve coverage. > > Something like this would be nice: > > CREATE TABLE t1 (a VARCHAR(10), b VARCHAR(10), c VARCHAR(10)); INSERT INTO t1 > VALUES (NULL,NULL,NULL); INSERT INTO t1 VALUES ('a',NULL,NULL); INSERT INTO > t1 VALUES (NULL,'b',NULL); INSERT INTO t1 VALUES (NULL,NULL,'c'); INSERT INTO > t1 VALUES ('a','b',NULL); INSERT INTO t1 VALUES (NULL,'b','c'); INSERT INTO > t1 VALUES ('a',NULL,'c'); SELECT a||b||c FROM t1; DROP TABLE t1; > > > >> diff --git a/mysql-test/suite/compat/oracle/t/func_concat.test >> b/mysql-test/suite/compat/oracle/t/func_concat.test >> new file mode 100644 >> index 0000000..8d84707 >> --- /dev/null >> +++ b/mysql-test/suite/compat/oracle/t/func_concat.test >> @@ -0,0 +1,17 @@ >> +# >> +# Testing CONCAT with null value >> +# >> + >> +SET sql_mode=ORACLE; >> + >> +SELECT 'a'||'b'; >> + >> +SELECT 'a'||'b'||NULL; >> + >> +SELECT NULL||'b'||NULL; >> + >> +SELECT NULL||NULL||'c'; >> + >> +SELECT NULL||NULL; >> + >> + >> diff --git a/scripts/mysql_system_tables.sql >> b/scripts/mysql_system_tables.sql index 7b61416..eb2c97f 100644 >> --- a/scripts/mysql_system_tables.sql >> +++ b/scripts/mysql_system_tables.sql >> @@ -80,7 +80,7 @@ CREATE TABLE IF NOT EXISTS time_zone_transition_type ( >> Time_zone_id int unsign >> >> CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint >> signed NOT NULL, Correction int signed NOT NULL, PRIMARY KEY TranTime >> (Transition_time) ) engine=MyISAM CHARACTER SET utf8 comment='Leap seconds >> information for time zones'; >> >> -CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT >> '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type >> enum('FUNCTION','PROCEDURE') NOT NULL, specific_name char(64) DEFAULT >> '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, >> sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', >> 'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic >> enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type >> enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob >> NOT NULL, returns longblob NOT NULL, body longblob NOT NULL, definer >> char(141) collate utf8_bin DEFAULT '' NOT NULL, created timestamp NOT >> NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, modified >> timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', sql_mode set( >> 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', 'ANSI_QUOTES', 'IGNORE_SPACE', >> 'IGNORE_BAD_TABLE_OPTIONS', 'ONLY_FULL_GROUP_BY', >> 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', 'POSTGRESQL', 'ORACLE', >> 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', 'NO_TABLE_OPTIONS', >> 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', 'ANSI', >> 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', >> 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', >> 'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', >> 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE', >> 'NO_ENGINE_SUBSTITUTION', 'PAD_CHAR_TO_FULL_LENGTH') DEFAULT '' NOT >> NULL, comment text collate utf8_bin NOT NULL, character_set_client >> char(32) collate utf8_bin, collation_connection char(32) collate >> utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, >> PRIMARY KEY (db,name,type)) engine=MyISAM character set utf8 >> comment='Stored Procedures'; >> +CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT >> +'' NOT NULL, name char(64) DEFAULT '' NOT NULL, type >> +enum('FUNCTION','PROCEDURE') NOT NULL, specific_name char(64) DEFAULT >> +'' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, >> +sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', >> +'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, >> +is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, >> +security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, >> +param_list blob NOT NULL, returns longblob NOT NULL, body longblob >> +NOT NULL, definer char(141) collate utf8_bin DEFAULT '' NOT NULL, >> +created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE >> +CURRENT_TIMESTAMP, modified timestamp NOT NULL DEFAULT '0000-00-00 >> +00:00:00', sql_mode set( 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', >> +'ANSI_QUOTES', 'IGNORE_SPACE', 'IGNORE_BAD_TABLE_OPTIONS', >> +'ONLY_FULL_GROUP_BY', 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', >> +'POSTGRESQL', 'ORACLE', 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', >> +'NO_TABLE_OPTIONS', 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', >> +'ANSI', 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', >> +'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', >> +'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', >> +'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE', >> +'NO_ENGINE_SUBSTITUTION', >> +'PAD_CHAR_TO_FULL_LENGTH','CONCAT_NULL_YIELDS_NULL_OFF') DEFAULT '' >> +NOT NULL, comment text collate utf8_bin NOT NULL, >> +character_set_client char(32) collate utf8_bin, collation_connection >> +char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, >> +body_utf8 longblob, PRIMARY KEY (db,name,type)) engine=MyISAM >> +character set utf8 comment='Stored Procedures'; >> >> CREATE TABLE IF NOT EXISTS procs_priv ( Host char(60) binary DEFAULT '' NOT >> NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(80) binary DEFAULT >> '' NOT NULL, Routine_name char(64) COLLATE utf8_general_ci DEFAULT '' NOT >> NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor char(141) >> DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') >> COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL >> DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY >> (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) >> engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure >> privileges'; >> >> @@ -101,7 +101,7 @@ PREPARE stmt FROM @str; EXECUTE stmt; DROP >> PREPARE stmt; >> >> -CREATE TABLE IF NOT EXISTS event ( db char(64) CHARACTER SET utf8 >> COLLATE utf8_bin NOT NULL default '', name char(64) CHARACTER SET utf8 >> NOT NULL default '', body longblob NOT NULL, definer char(141) >> CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', execute_at >> DATETIME default NULL, interval_value int(11) default NULL, >> interval_field >> ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND','M >> ICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MI >> NUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECON >> D','MINUTE_MICROSECOND','SECOND_MICROSECOND') default NULL, created >> TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE >> CURRENT_TIMESTAMP, modified TIMESTAMP NOT NULL DEFAULT '0000-00-00 >> 00:00:00', last_executed DATETIME default NULL, starts DATETIME >> default NULL, ends DATETIME default NULL, status >> ENUM('ENABLED','DISABLED','SLAVESIDE_DISABLED') NOT NULL default >> 'ENABLED', on_completion ENUM('DROP','PRESERVE') NOT NULL default >> 'DROP', sql_mode >> set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','IG >> NORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION' >> ,'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KE >> Y_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40', >> 'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TA >> BLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DA >> TES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER', >> 'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGT >> H') DEFAULT '' NOT NULL, comment char(64) CHARACTER SET utf8 COLLATE >> utf8_bin NOT NULL default '', originator INTEGER UNSIGNED NOT NULL, >> time_zone char(64) CHARACTER SET latin1 NOT NULL DEFAULT 'SYSTEM', >> character_set_client char(32) collate utf8_bin, collation_connection >> char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, >> body_utf8 longblob, PRIMARY KEY (db, name) ) ENGINE=MyISAM DEFAULT >> CHARSET=utf8 COMMENT 'Events'; >> +CREATE TABLE IF NOT EXISTS event ( db char(64) CHARACTER SET utf8 >> +COLLATE utf8_bin NOT NULL default '', name char(64) CHARACTER SET >> +utf8 NOT NULL default '', body longblob NOT NULL, definer char(141) >> +CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', execute_at >> +DATETIME default NULL, interval_value int(11) default NULL, >> +interval_field >> +ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK','SECOND',' >> +MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_ >> +MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSE >> +COND','MINUTE_MICROSECOND','SECOND_MICROSECOND') default NULL, >> +created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE >> +CURRENT_TIMESTAMP, modified TIMESTAMP NOT NULL DEFAULT '0000-00-00 >> +00:00:00', last_executed DATETIME default NULL, starts DATETIME >> +default NULL, ends DATETIME default NULL, status >> +ENUM('ENABLED','DISABLED','SLAVESIDE_DISABLED') NOT NULL default >> +'ENABLED', on_completion ENUM('DROP','PRESERVE') NOT NULL default >> +'DROP', sql_mode >> +set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','I >> +GNORE_BAD_TABLE_OPTIONS','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTIO >> +N','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO >> +_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL >> +40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRA >> +NS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVA >> +LID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE >> +_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FU >> +LL_LENGTH','CONCAT_NULL_YIELDS_NULL_OFF') DEFAULT '' NOT NULL, >> +comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default >> +'', originator INTEGER UNSIGNED NOT NULL, time_zone char(64) >> +CHARACTER SET latin1 NOT NULL DEFAULT 'SYSTEM', character_set_client >> +char(32) collate utf8_bin, collation_connection char(32) collate >> +utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, >> +PRIMARY KEY (db, name) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT >> +'Events'; >> >> SET @create_innodb_table_stats="CREATE TABLE IF NOT EXISTS >> innodb_table_stats ( >> database_name VARCHAR(64) NOT NULL, >> diff --git a/scripts/mysql_system_tables_fix.sql >> b/scripts/mysql_system_tables_fix.sql >> index ea1059c..b3c0ce9 100644 >> --- a/scripts/mysql_system_tables_fix.sql >> +++ b/scripts/mysql_system_tables_fix.sql >> @@ -442,7 +442,8 @@ ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT >> NULL, >> 'NO_AUTO_CREATE_USER', >> 'HIGH_NOT_PRECEDENCE', >> 'NO_ENGINE_SUBSTITUTION', >> - 'PAD_CHAR_TO_FULL_LENGTH' >> + 'PAD_CHAR_TO_FULL_LENGTH', >> + 'CONCAT_NULL_YIELDS_NULL_OFF' >> ) DEFAULT '' NOT NULL, >> DEFAULT CHARACTER SET utf8; >> >> diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc >> index 9de55c4..c279a85 100644 >> --- a/sql/event_db_repository.cc >> +++ b/sql/event_db_repository.cc >> @@ -123,7 +123,7 @@ const TABLE_FIELD_TYPE >> event_table_fields[ET_FIELD_COUNT] = >> >> "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES'," >> "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES'," >> "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER'," >> - >> "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") >> }, >> + >> + "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LE >> + NGTH','CONCAT_NULL_YIELDS_NULL_OFF')") }, >> {NULL, 0} >> }, >> { >> diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index >> fe1c470..7b22f4b 100644 >> --- a/sql/item_strfunc.cc >> +++ b/sql/item_strfunc.cc >> @@ -619,19 +619,42 @@ String *Item_func_concat::val_str(String *str) >> DBUG_ASSERT(fixed == 1); >> String *res,*res2,*use_as_buff; >> uint i; >> - bool is_const= 0; >> + bool is_const = 0; > > Please follow the MariaDB coding style: > > 1. In assignment operator: > - there is no space before "=" > - there is one space after "=". > > So the above line "bool is_const= 0;" should not be modified. > > 2. Don't use tabs, use spaces instead. > > 3. There should not be trailing white spaces. > Please use "git diff --check". > > > Note, the old code may not always be following the coding style. > So don't be confused :) Some lines are old enough, older than the coding > style policy. > > Please make sure that all new and modified line follows the coding style. > > >> + uint firstarg = 0; >> + uint nextarg = 1; > > These two variables basically repeat each other, and repeat "i". > > Also, I noticed that args[0]->val_str() is called twice. > > One time in the "// Search first non null argument" loop, and then before the > "for (i= nextarg; i < arg_count ; i++)" again. > > I suggest to remove firstarg and nextarg and always use "i" instead, and to > make sure that val_str() is not called twice for the same argument. > > > >> >> - null_value=0; >> - if (!(res=args[0]->val_str(str))) >> + if (current_thd->variables.sql_mode & >> + MODE_CONCAT_NULL_YIELDS_NULL_OFF) > > current_thd is a heavy function. > It's better to avoid its execution per row. > Please add a new boolean member and initialize it to false in constructors: > > > class Item_func_concat :public Item_str_func { > m_null_yierds_not_null; > String tmp_value; > public: > Item_func_concat(THD *thd, List<Item> &list): > Item_str_func(thd, list), > m_null_yield_not_null(false) > {} > Item_func_concat(THD *thd, Item *a, Item *b): > Item_str_func(thd, a, b), > m_null_yield_not_null(false) > {} > ... > }; > > > and then set it according to sql_mode in fix_length_and_dec(): > > > > void Item_func_concat::fix_length_and_dec() > { > m_null_yields_not_null= current_thd->variables.sql_mode & > MODE_CONCAT_NULL_YIELDS_NULL_OFF; > ... > } > > > After this, we change all tests like: > > if (current_thd->variables.sql_mode & MODE_CONCAT_NULL_YIELDS_NULL_OFF) > > to > > if (m_null_yields_not_null) > > >> + { >> + // Search first non null argument >> + i = 0; >> + while (!(res = args[i]->val_str(str))) >> + { >> + if (++i == arg_count) >> + break; >> + } >> + if (res) >> + { >> + firstarg=i++; >> + nextarg = i; >> + } >> + } > > I find something like this more readable: > > ... > // Search first non null argument > for (i= 0; i < arg_count; i++) > { > if ((res= args[i]->val_str(str)) > break; > } > if (i == arg_count) > goto null; > ... > > >> + >> + null_value = 0; >> + if (!(res = args[firstarg]->val_str(str))) > > There are tabs in the above two lines. Please use spaces. > > >> goto null; >> - use_as_buff= &tmp_value; >> - is_const= args[0]->const_item(); >> - for (i=1 ; i < arg_count ; i++) >> + use_as_buff = &tmp_value; >> + is_const = args[firstarg]->const_item(); >> + >> + for (i= nextarg; i < arg_count ; i++) >> { >> if (res->length() == 0) >> { >> - if (!(res=args[i]->val_str(str))) >> - goto null; >> + if (!(res = args[i]->val_str(str))) >> + { >> + if (current_thd->variables.sql_mode & >> + MODE_CONCAT_NULL_YIELDS_NULL_OFF) > > if (m_null_yields_not_null) > >> + continue; >> + goto null; >> + } >> /* >> CONCAT accumulates its result in the result of its the first >> non-empty argument. Because of this we need is_const to be @@ >> -641,8 +664,12 @@ String *Item_func_concat::val_str(String *str) >> } >> else >> { >> - if (!(res2=args[i]->val_str(use_as_buff))) >> - goto null; >> + if (!(res2 = args[i]->val_str(use_as_buff))) >> + { >> + if (current_thd->variables.sql_mode & >> + MODE_CONCAT_NULL_YIELDS_NULL_OFF) > > if (m_null_yields_not_null) > > >> + continue; >> + goto null; >> + } >> if (res2->length() == 0) >> continue; >> if (res->length()+res2->length() > diff --git a/sql/sp.cc >> b/sql/sp.cc index eb542a6..288b7a9 100644 >> --- a/sql/sp.cc >> +++ b/sql/sp.cc >> @@ -130,7 +130,7 @@ TABLE_FIELD_TYPE >> proc_table_fields[MYSQL_PROC_FIELD_COUNT] = >> >> "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES'," >> "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES'," >> "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER'," >> - >> "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") >> }, >> + >> + "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LE >> + NGTH','CONCAT_NULL_YIELDS_NULL_OFF')") }, >> { NULL, 0 } >> }, >> { >> diff --git a/sql/sql_class.h b/sql/sql_class.h index 6f8e884..c754092 >> 100644 >> --- a/sql/sql_class.h >> +++ b/sql/sql_class.h >> @@ -139,6 +139,7 @@ enum enum_binlog_row_image { >> #define MODE_HIGH_NOT_PRECEDENCE (1ULL << 29) >> #define MODE_NO_ENGINE_SUBSTITUTION (1ULL << 30) >> #define MODE_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31) >> +#define MODE_CONCAT_NULL_YIELDS_NULL_OFF (1ULL << 32) >> >> /* Bits for different old style modes */ >> #define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE (1 << 0) >> diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 27e6463..c51b1de3 >> 100644 >> --- a/sql/sys_vars.cc >> +++ b/sql/sys_vars.cc >> @@ -3032,7 +3032,8 @@ export sql_mode_t expand_sql_mode(sql_mode_t sql_mode) >> sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | >> MODE_IGNORE_SPACE | >> MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | >> - MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER); >> + MODE_NO_FIELD_OPTIONS | MODE_NO_AUTO_CREATE_USER | >> + MODE_CONCAT_NULL_YIELDS_NULL_OFF); >> if (sql_mode & MODE_MSSQL) >> sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | >> MODE_IGNORE_SPACE | >> @@ -3097,7 +3098,7 @@ static const char *sql_mode_names[]= >> "STRICT_ALL_TABLES", "NO_ZERO_IN_DATE", "NO_ZERO_DATE", >> "ALLOW_INVALID_DATES", "ERROR_FOR_DIVISION_BY_ZERO", "TRADITIONAL", >> "NO_AUTO_CREATE_USER", "HIGH_NOT_PRECEDENCE", >> "NO_ENGINE_SUBSTITUTION", >> - "PAD_CHAR_TO_FULL_LENGTH", >> + "PAD_CHAR_TO_FULL_LENGTH","CONCAT_NULL_YIELDS_NULL_OFF", >> 0 >> }; >> >> diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index c7f148a..fc93534 >> 100644 >> --- a/sql/sys_vars.ic >> +++ b/sql/sys_vars.ic >> @@ -1228,7 +1228,7 @@ class Sys_var_flagset: public Sys_var_typelib >> global_var(ulonglong)= def_val; >> SYSVAR_ASSERT(typelib.count > 1); >> SYSVAR_ASSERT(typelib.count <= 65); >> - SYSVAR_ASSERT(def_val < my_set_bits(typelib.count)); >> + SYSVAR_ASSERT(def_val < my_set_bits64(typelib.count)); >> SYSVAR_ASSERT(strcmp(values[typelib.count-1], "default") == 0); >> SYSVAR_ASSERT(size == sizeof(ulonglong)); >> } >> @@ -1276,7 +1276,7 @@ class Sys_var_flagset: public Sys_var_typelib >> { >> longlong tmp=var->value->val_int(); >> if ((tmp < 0 && ! var->value->unsigned_flag) >> - || (ulonglong)tmp > my_set_bits(typelib.count)) >> + || (ulonglong)tmp > my_set_bits64(typelib.count)) >> return true; >> else >> var->save_result.ulonglong_value= tmp; @@ -1337,7 +1337,7 @@ >> class Sys_var_set: public Sys_var_typelib >> global_var(ulonglong)= def_val; >> SYSVAR_ASSERT(typelib.count > 0); >> SYSVAR_ASSERT(typelib.count <= 64); >> - SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count)); >> + SYSVAR_ASSERT(def_val <= my_set_bits64(typelib.count)); >> SYSVAR_ASSERT(size == sizeof(ulonglong)); >> } >> bool do_check(THD *thd, set_var *var) @@ -1375,7 +1375,7 @@ class >> Sys_var_set: public Sys_var_typelib >> { >> longlong tmp=var->value->val_int(); >> if ((tmp < 0 && ! var->value->unsigned_flag) >> - || (ulonglong)tmp > my_set_bits(typelib.count)) >> + || (ulonglong)tmp > my_set_bits64(typelib.count)) >> return true; >> else >> var->save_result.ulonglong_value= tmp; >> -- >> 2.6.3.windows.1 _______________________________________________ Mailing list: https://launchpad.net/~maria-developers Post to : maria-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~maria-developers More help : https://help.launchpad.net/ListHelp