← Back to team overview

maria-developers team mailing list archive

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','MICROSECOND','YEAR_MONTH','DAY_HOUR','DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND','DAY_MICROSECOND','HOUR_MICROSECOND','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','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 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_MICROSECOND','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','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 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_LENGTH','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_LENGTH','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

Follow ups

References