List:Commits« Previous MessageNext Message »
From:Dmitry Shulga Date:October 18 2012 3:13pm
Subject:bzr push into mysql-trunk branch (Dmitry.Shulga:4183 to 4184) WL#6030
View as plain text  
 4184 Dmitry Shulga	2012-10-18
      WL#6030

    modified:
      mysql-test/r/insert_select.result
      mysql-test/r/key.result
      mysql-test/r/null.result
      mysql-test/r/warnings.result
      mysql-test/suite/funcs_1/r/innodb_trig_09.result
      mysql-test/suite/funcs_1/r/memory_trig_09.result
      mysql-test/suite/funcs_1/r/myisam_trig_09.result
      sql/field.cc
      sql/field.h
      sql/field_conv.cc
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster_cond.h
      sql/item.cc
      sql/item.h
      sql/item_cmpfunc.cc
      sql/item_func.h
      sql/item_sum.cc
      sql/opt_range.cc
      sql/partition_info.cc
      sql/rpl_record.cc
      sql/rpl_record_old.cc
      sql/sp.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_executor.cc
      sql/sql_handler.cc
      sql/sql_insert.cc
      sql/sql_insert.h
      sql/sql_load.cc
      sql/sql_tmp_table.cc
      sql/sql_trigger.cc
      sql/sql_trigger.h
      sql/sql_union.cc
      sql/sql_update.cc
      sql/table.cc
      sql/table.h
      sql/unireg.cc
      tests/mysql_client_test.c
      unittest/gunit/field_date-t.cc
      unittest/gunit/field_datetime-t.cc
      unittest/gunit/field_long-t.cc
      unittest/gunit/field_newdecimal-t.cc
      unittest/gunit/mock_field_timestamp.h
      unittest/gunit/mock_field_timestampf.h
 4183 Alexander Nozdrin	2012-10-18
      Fake empty changeset to trigger rebuild.

=== modified file 'mysql-test/r/insert_select.result'
--- a/mysql-test/r/insert_select.result	2012-02-29 11:17:52 +0000
+++ b/mysql-test/r/insert_select.result	2012-10-18 14:55:03 +0000
@@ -607,7 +607,6 @@ create table t2(No int not null, Field i
 insert into t2 Select null, Field, Count From t1 Where Month=20030901 and Type=2;
 Warnings:
 Warning	1048	Column 'No' cannot be null
-Warning	1048	Column 'No' cannot be null
 select * from t2;
 No	Field	Count
 0	1	100

=== modified file 'mysql-test/r/key.result'
--- a/mysql-test/r/key.result	2012-07-31 14:14:52 +0000
+++ b/mysql-test/r/key.result	2012-10-18 14:55:03 +0000
@@ -160,7 +160,6 @@ UNIQUE (c,i));
 INSERT INTO t1 (c) VALUES (NULL),(NULL);
 Warnings:
 Warning	1048	Column 'c' cannot be null
-Warning	1048	Column 'c' cannot be null
 SELECT * FROM t1;
 c	i
 	1

=== modified file 'mysql-test/r/null.result'
--- a/mysql-test/r/null.result	2011-07-19 15:11:15 +0000
+++ b/mysql-test/r/null.result	2012-10-18 14:55:03 +0000
@@ -105,7 +105,6 @@ ERROR 23000: Column 'a' cannot be null
 INSERT INTO t1 (a) values (null),(null);
 Warnings:
 Warning	1048	Column 'a' cannot be null
-Warning	1048	Column 'a' cannot be null
 INSERT INTO t1 (b) values (null);
 ERROR 23000: Column 'b' cannot be null
 INSERT INTO t1 (b) values (1/null);
@@ -113,7 +112,6 @@ ERROR 23000: Column 'b' cannot be null
 INSERT INTO t1 (b) values (null),(null);
 Warnings:
 Warning	1048	Column 'b' cannot be null
-Warning	1048	Column 'b' cannot be null
 INSERT INTO t1 (c) values (null);
 ERROR 23000: Column 'c' cannot be null
 INSERT INTO t1 (c) values (1/null);
@@ -121,7 +119,6 @@ ERROR 23000: Column 'c' cannot be null
 INSERT INTO t1 (c) values (null),(null);
 Warnings:
 Warning	1048	Column 'c' cannot be null
-Warning	1048	Column 'c' cannot be null
 INSERT INTO t1 (d) values (null);
 ERROR 23000: Column 'd' cannot be null
 INSERT INTO t1 (d) values (1/null);
@@ -129,7 +126,6 @@ ERROR 23000: Column 'd' cannot be null
 INSERT INTO t1 (d) values (null),(null);
 Warnings:
 Warning	1048	Column 'd' cannot be null
-Warning	1048	Column 'd' cannot be null
 select * from t1;
 a	b	c	d
 	0	0000-00-00 00:00:00	0

=== modified file 'mysql-test/r/warnings.result'
--- a/mysql-test/r/warnings.result	2011-04-15 12:14:35 +0000
+++ b/mysql-test/r/warnings.result	2012-10-18 14:55:03 +0000
@@ -119,13 +119,13 @@ Warning	1048	Column 'a' cannot be null
 Warning	1265	Data truncated for column 'b' at row 4
 insert into t2(b) values('mysqlab');
 Warnings:
-Warning	1364	Field 'a' doesn't have a default value
 Warning	1265	Data truncated for column 'b' at row 1
+Warning	1364	Field 'a' doesn't have a default value
 set sql_warnings=1;
 insert into t2(b) values('mysqlab');
 Warnings:
-Warning	1364	Field 'a' doesn't have a default value
 Warning	1265	Data truncated for column 'b' at row 1
+Warning	1364	Field 'a' doesn't have a default value
 set sql_warnings=0;
 drop table t1, t2;
 create table t1(a char(10));

=== modified file 'mysql-test/suite/funcs_1/r/innodb_trig_09.result'
--- a/mysql-test/suite/funcs_1/r/innodb_trig_09.result	2009-02-05 13:51:00 +0000
+++ b/mysql-test/suite/funcs_1/r/innodb_trig_09.result	2012-10-18 14:55:03 +0000
@@ -198,7 +198,7 @@ a	NULL	Test 3.5.9.4-trig	00000	999	NULL
 select  @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
 @tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
 @tr_var_b4_118	@tr_var_b4_121	@tr_var_b4_122	@tr_var_b4_136	@tr_var_b4_151	@tr_var_b4_163
-a	NULL	Test 3.5.9.4-trig	0	999	NULL
+a	NULL	Test 3.5.9.4-trig	NULL	999	NULL
 select  @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
 @tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
 @tr_var_af_118	@tr_var_af_121	@tr_var_af_122	@tr_var_af_136	@tr_var_af_151	@tr_var_af_163

=== modified file 'mysql-test/suite/funcs_1/r/memory_trig_09.result'
--- a/mysql-test/suite/funcs_1/r/memory_trig_09.result	2009-02-05 13:51:00 +0000
+++ b/mysql-test/suite/funcs_1/r/memory_trig_09.result	2012-10-18 14:55:03 +0000
@@ -199,7 +199,7 @@ a	NULL	Test 3.5.9.4-trig	00000	999	NULL
 select  @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
 @tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
 @tr_var_b4_118	@tr_var_b4_121	@tr_var_b4_122	@tr_var_b4_136	@tr_var_b4_151	@tr_var_b4_163
-a	NULL	Test 3.5.9.4-trig	0	999	NULL
+a	NULL	Test 3.5.9.4-trig	NULL	999	NULL
 select  @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
 @tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
 @tr_var_af_118	@tr_var_af_121	@tr_var_af_122	@tr_var_af_136	@tr_var_af_151	@tr_var_af_163

=== modified file 'mysql-test/suite/funcs_1/r/myisam_trig_09.result'
--- a/mysql-test/suite/funcs_1/r/myisam_trig_09.result	2009-02-05 13:51:00 +0000
+++ b/mysql-test/suite/funcs_1/r/myisam_trig_09.result	2012-10-18 14:55:03 +0000
@@ -199,7 +199,7 @@ a	NULL	Test 3.5.9.4-trig	00000	999	NULL
 select  @tr_var_b4_118, @tr_var_b4_121, @tr_var_b4_122,
 @tr_var_b4_136, @tr_var_b4_151, @tr_var_b4_163;
 @tr_var_b4_118	@tr_var_b4_121	@tr_var_b4_122	@tr_var_b4_136	@tr_var_b4_151	@tr_var_b4_163
-a	NULL	Test 3.5.9.4-trig	0	999	NULL
+a	NULL	Test 3.5.9.4-trig	NULL	999	NULL
 select  @tr_var_af_118, @tr_var_af_121, @tr_var_af_122,
 @tr_var_af_136, @tr_var_af_151, @tr_var_af_163;
 @tr_var_af_118	@tr_var_af_121	@tr_var_af_122	@tr_var_af_136	@tr_var_af_151	@tr_var_af_163

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2012-06-29 14:40:34 +0000
+++ b/sql/field.cc	2012-10-18 14:55:03 +0000
@@ -924,6 +924,18 @@ static enum_field_types field_types_merg
 
 
 /**
+  Set field to temporary value NULL.
+*/
+void Field::set_tmp_null()
+{
+  m_is_tmp_null= true;
+
+  m_count_cuted_fields_saved= table ? table->in_use->count_cuted_fields :
+                                      current_thd->count_cuted_fields;
+}
+
+
+/**
   Return type of which can carry value of both given types in UNION result.
 
   @param a  type for merging
@@ -1351,20 +1363,121 @@ String *Field::val_int_as_str(String *va
 Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
 	     uchar null_bit_arg,
 	     utype unireg_check_arg, const char *field_name_arg)
-  :ptr(ptr_arg), null_ptr(null_ptr_arg),
+  :ptr(ptr_arg),
+   m_null_ptr(null_ptr_arg),
+   m_is_tmp_nullable(false),
+   m_is_tmp_null(false),
    table(0), orig_table(0), table_name(0),
    field_name(field_name_arg),
    unireg_check(unireg_check_arg),
    field_length(length_arg), null_bit(null_bit_arg), 
-   is_created_from_null_item(FALSE)
+   is_created_from_null_item(FALSE),
+   m_warnings_pushed(0)
 {
-  flags=null_ptr ? 0: NOT_NULL_FLAG;
+  flags=real_maybe_null() ? 0: NOT_NULL_FLAG;
   comment.str= (char*) "";
   comment.length=0;
   field_index= 0;
 }
 
 
+/**
+  Check NOT NULL constraint on the field after temporary nullability is
+  disabled.
+
+  @param warning_no Warning to report.
+
+  @return TYPE_OK if the value is Ok, or corresponding error code from
+  the type_conversion_status enum.
+*/
+type_conversion_status Field::check_constraints(int mysql_errno)
+{
+  /*
+    Ensure that Field::check_constraints() is called only when temporary
+    nullability is disabled.
+  */
+
+  DBUG_ASSERT(!is_tmp_nullable());
+
+  if (real_maybe_null())
+    return TYPE_OK; // If the field is nullable, we're Ok.
+
+  if (!m_is_tmp_null)
+    return TYPE_OK; // If the field was not NULL, we're Ok.
+
+  // The field has been set to NULL.
+
+  /*
+    If the field is of AUTO_INCREMENT, and the next number
+    has been assigned to it, we're Ok.
+  */
+
+  if (this == table->next_number_field)
+    return TYPE_OK;
+
+  /*
+    If the field is of TIMESTAMP its default value is CURRENT_TIMESTAMP,
+    so we're OK.
+  */
+
+  if (type() == MYSQL_TYPE_TIMESTAMP)
+    return TYPE_OK;
+
+  switch (m_count_cuted_fields_saved) {
+  case CHECK_FIELD_WARN:
+    set_warning(Sql_condition::WARN_LEVEL_WARN, mysql_errno, 1);
+    /* fall through */
+  case CHECK_FIELD_IGNORE:
+    return TYPE_OK;
+  case CHECK_FIELD_ERROR_FOR_NULL:
+    if (!table->in_use->no_errors)
+      my_error(ER_BAD_NULL_ERROR, MYF(0), field_name);
+    return TYPE_ERR_NULL_CONSTRAINT_VIOLATION;
+  }
+
+  DBUG_ASSERT(0); // impossible
+  return TYPE_ERR_NULL_CONSTRAINT_VIOLATION;
+}
+
+
+/**
+  Set field to value NULL.
+
+  @param row_offset    This is the offset between the row being updated
+                       and table->record[0]
+*/
+void Field::set_null(my_ptrdiff_t row_offset)
+{
+  if (real_maybe_null())
+  {
+    m_null_ptr[row_offset]|= null_bit;
+  }
+  else if (is_tmp_nullable())
+  {
+    set_tmp_null();
+  }
+}
+
+
+/**
+  Set field to value NOT NULL.
+
+  @param row_offset    This is the offset between the row being updated
+                       and table->record[0]
+*/
+void Field::set_notnull(my_ptrdiff_t row_offset)
+{
+  if (real_maybe_null())
+  {
+    m_null_ptr[row_offset]&= (uchar) ~null_bit;
+  }
+  else if (is_tmp_nullable())
+  {
+    reset_tmp_null();
+  }
+}
+
+
 void Field::hash(ulong *nr, ulong *nr2)
 {
   if (is_null())
@@ -1379,24 +1492,24 @@ void Field::hash(ulong *nr, ulong *nr2)
   }
 }
 
-size_t
-Field::do_last_null_byte() const
+size_t Field::do_last_null_byte() const
 {
-  DBUG_ASSERT(null_ptr == NULL || null_ptr >= table->record[0]);
-  if (null_ptr)
-    return null_offset() + 1;
-  return LAST_NULL_BYTE_UNDEF;
+  DBUG_ASSERT(!real_maybe_null() || m_null_ptr >= table->record[0]);
+  return real_maybe_null() ? null_offset() + 1 : (size_t) LAST_NULL_BYTE_UNDEF;
 }
 
 
-void Field::copy_from_tmp(int row_offset)
+void Field::copy_data(my_ptrdiff_t src_record_offset)
 {
-  memcpy(ptr,ptr+row_offset,pack_length());
-  if (null_ptr)
+  memcpy(ptr, ptr + src_record_offset, pack_length());
+
+  if (real_maybe_null())
   {
-    *null_ptr= (uchar) ((null_ptr[0] & (uchar) ~(uint) null_bit) |
-			(null_ptr[row_offset] & (uchar) null_bit));
-  }
+    // Set to NULL if the source record is NULL, otherwise set to NOT-NULL.
+    m_null_ptr[0]= (m_null_ptr[0]                 & ~null_bit) |
+                   (m_null_ptr[src_record_offset] &  null_bit);
+  } else if (is_tmp_nullable())
+    m_is_tmp_null= false;
 }
 
 
@@ -1894,7 +2007,7 @@ Field *Field::new_key_field(MEM_ROOT *ro
   if ((tmp= new_field(root, new_table, table == new_table)))
   {
     tmp->ptr=      new_ptr;
-    tmp->null_ptr= new_null_ptr;
+    tmp->m_null_ptr= new_null_ptr;
     tmp->null_bit= new_null_bit;
   }
   return tmp;
@@ -6511,7 +6624,7 @@ Field_longstr::check_string_copy_error(c
                                        const char *from_end_pos,
                                        const char *end,
                                        bool count_spaces,
-                                       const CHARSET_INFO *cs) const
+                                       const CHARSET_INFO *cs)
 {
   const char *pos;
   char tmp[32];
@@ -6555,7 +6668,7 @@ Field_longstr::check_string_copy_error(c
 
 type_conversion_status
 Field_longstr::report_if_important_data(const char *pstr, const char *end,
-                                        bool count_spaces) const
+                                        bool count_spaces)
 {
   if ((pstr < end) && table->in_use->count_cuted_fields)
   {
@@ -8874,7 +8987,7 @@ Field_bit::Field_bit(uchar *ptr_arg, uin
   flags|= UNSIGNED_FLAG;
   /*
     Ensure that Field::eq() can distinguish between two different bit fields.
-    (two bit fields that are not null, may have same ptr and null_ptr)
+    (two bit fields that are not null, may have same ptr and m_null_ptr)
   */
   if (!null_ptr_arg)
     null_bit= bit_ofs_arg;
@@ -8912,9 +9025,9 @@ Field_bit::do_last_null_byte() const
   */
   DBUG_PRINT("test", ("bit_ofs: %d, bit_len: %d  bit_ptr: 0x%lx",
                       bit_ofs, bit_len, (long) bit_ptr));
-  uchar *result;
+  const uchar *result;
   if (bit_len == 0)
-    result= null_ptr;
+    result= get_null_ptr();
   else if (bit_ofs + bit_len > 8)
     result= bit_ptr + 1;
   else
@@ -9372,7 +9485,7 @@ void Field_bit::set_default()
 {
   if (bit_len > 0)
   {
-    my_ptrdiff_t const offset= table->s->default_values - table->record[0];
+    my_ptrdiff_t offset= table->default_values_offset();
     uchar bits= get_rec_bits(bit_ptr + offset, bit_ofs, bit_len);
     set_rec_bits(bits, bit_ptr, bit_ofs, bit_len);
   }
@@ -10360,11 +10473,9 @@ Create_field::Create_field(Field *old_fi
   {
     char buff[MAX_FIELD_WIDTH];
     String tmp(buff,sizeof(buff), charset);
-    my_ptrdiff_t diff;
 
     /* Get the value from default_values */
-    diff= (my_ptrdiff_t) (orig_field->table->s->default_values-
-                          orig_field->table->record[0]);
+    my_ptrdiff_t diff= orig_field->table->default_values_offset();
     orig_field->move_field_offset(diff);	// Points now at default_values
     if (!orig_field->is_real_null())
     {
@@ -10442,12 +10553,17 @@ uint32 Field_blob::max_display_length()
  Warning handling
 *****************************************************************************/
 
+
 /**
   Produce warning or note about data saved into field.
 
   @param level            - level of message (Note/Warning/Error)
   @param code             - error code of message to be produced
   @param cut_increment    - whenever we should increase cut fields count
+  @param view_db_name     - if set this is the database name for view
+                            that causes the warning
+  @param view_name        - if set this is the name of view that causes
+                            the warning
 
   @note
     This function won't produce warning and increase cut fields counter
@@ -10456,29 +10572,84 @@ uint32 Field_blob::max_display_length()
     if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes.
     This allows us to avoid notes in optimisation, like convert_constant_item().
 
+    In case of execution statements INSERT/INSERT SELECT/REPLACE/REPLACE SELECT
+    the method emits only one warning message for the following
+    types of warning: ER_BAD_NULL_ERROR, ER_WARN_NULL_TO_NOTNULL,
+    ER_NO_DEFAULT_FOR_FIELD.
   @retval
     1 if count_cuted_fields == CHECK_FIELD_IGNORE and error level is not NOTE
   @retval
     0 otherwise
 */
 
-bool 
-Field::set_warning(Sql_condition::enum_warning_level level, uint code,
-                   int cut_increment) const
+bool Field::set_warning(Sql_condition::enum_warning_level level,
+                        uint code,
+                        int cut_increment,
+                        const char *view_db_name,
+                        const char *view_name)
 {
   /*
     If this field was created only for type conversion purposes it
     will have table == NULL.
   */
+
   THD *thd= table ? table->in_use : current_thd;
-  if (thd->count_cuted_fields)
+
+  if (!thd->count_cuted_fields)
+    return level >= Sql_condition::WARN_LEVEL_WARN;
+
+  thd->cuted_fields+= cut_increment;
+
+  if (thd->lex->sql_command != SQLCOM_INSERT &&
+      thd->lex->sql_command != SQLCOM_INSERT_SELECT &&
+      thd->lex->sql_command != SQLCOM_REPLACE &&
+      thd->lex->sql_command != SQLCOM_REPLACE_SELECT)
   {
-    thd->cuted_fields+= cut_increment;
+    // We aggregate warnings from only INSERT and REPLACE statements.
+
     push_warning_printf(thd, level, code, ER(code), field_name,
                         thd->get_stmt_da()->current_row_for_warning());
+
     return 0;
   }
-  return level >= Sql_condition::WARN_LEVEL_WARN;
+
+  unsigned int current_warning_mask= 0;
+
+  if (code == ER_BAD_NULL_ERROR)
+    current_warning_mask= BAD_NULL_ERROR_PUSHED;
+  else if (code == ER_WARN_NULL_TO_NOTNULL)
+    current_warning_mask= WARN_NULL_TO_NOTNULL_PUSHED;
+  else if (code == ER_NO_DEFAULT_FOR_FIELD)
+    current_warning_mask= NO_DEFAULT_FOR_FIELD_PUSHED;
+
+  if (current_warning_mask)
+  {
+    if (!(m_warnings_pushed & current_warning_mask))
+    {
+      push_warning_printf(thd, level, code, ER(code), field_name,
+                          thd->get_stmt_da()->current_row_for_warning());
+      m_warnings_pushed|= current_warning_mask;
+    }
+  }
+  else if (code == ER_NO_DEFAULT_FOR_VIEW_FIELD)
+  {
+    if (!(m_warnings_pushed & NO_DEFAULT_FOR_VIEW_FIELD_PUSHED))
+    {
+      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+                          ER_NO_DEFAULT_FOR_VIEW_FIELD,
+                          ER(ER_NO_DEFAULT_FOR_VIEW_FIELD),
+                          view_db_name,
+                          view_name);
+      m_warnings_pushed|= NO_DEFAULT_FOR_VIEW_FIELD_PUSHED;
+    }
+  }
+  else
+  {
+    push_warning_printf(thd, level, code, ER(code), field_name,
+                        thd->get_stmt_da()->current_row_for_warning());
+  }
+
+  return 0;
 }
 
 

=== modified file 'sql/field.h'
--- a/sql/field.h	2012-06-22 10:11:31 +0000
+++ b/sql/field.h	2012-10-18 14:55:03 +0000
@@ -482,12 +482,40 @@ public:
 
   uchar		*ptr;			// Position to field in record
 
-protected:
+private:
   /**
      Byte where the @c NULL bit is stored inside a record. If this Field is a
      @c NOT @c NULL field, this member is @c NULL.
   */
-  uchar		*null_ptr;
+  uchar *m_null_ptr;
+
+  /**
+    Flag: if the NOT-NULL field can be temporary NULL.
+  */
+  bool m_is_tmp_nullable;
+
+  /**
+    This is a flag with the following semantics:
+      - it can be changed only when m_is_tmp_nullable is true;
+      - it specifies if this field in the first current record
+        (TABLE::record[0]) was set to NULL (temporary NULL).
+
+    This flag is used for trigger handling.
+  */
+  bool m_is_tmp_null;
+
+  /**
+    The value of THD::count_cuted_fields at the moment of setting
+    m_is_tmp_null attribute.
+  */
+  enum_check_fields m_count_cuted_fields_saved;
+
+protected:
+  const uchar *get_null_ptr() const
+  { return m_null_ptr; }
+
+  uchar *get_null_ptr() 
+  { return m_null_ptr; }
 
 public:
   /*
@@ -539,10 +567,75 @@ public:
    */
   bool is_created_from_null_item;
 
+private:
+  enum enum_pushed_warnings
+  {
+    BAD_NULL_ERROR_PUSHED= 1,
+    WARN_NULL_TO_NOTNULL_PUSHED= 2,
+    NO_DEFAULT_FOR_FIELD_PUSHED= 4,
+    NO_DEFAULT_FOR_VIEW_FIELD_PUSHED= 8
+  };
+
+  /*
+    Bitmask specifying which warnings have been already pushed in order
+    not to repeat the same warning for the collmn multiple times.
+    Uses values of enum_pushed_warnings to control pushed warnings.
+  */
+  unsigned int m_warnings_pushed;
+
+public:
   Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
         uchar null_bit_arg, utype unireg_check_arg,
         const char *field_name_arg);
-  virtual ~Field() {}
+
+  virtual ~Field()
+  { }
+
+  void reset_warnings()
+  { m_warnings_pushed= 0; }
+
+  /**
+    Turn on temporary nullability for the field.
+  */
+  void set_tmp_nullable()
+  {
+    m_is_tmp_nullable= true;
+  }
+
+  /**
+    Turn off temporary nullability for the field.
+  */
+  void reset_tmp_nullable()
+  {
+    m_is_tmp_nullable= false;
+  }
+
+  /**
+    Reset temporary NULL value for field
+  */
+  void reset_tmp_null()
+  {
+    m_is_tmp_null= false;
+  }
+
+  void set_tmp_null();
+
+  /**
+    @return temporary NULL-ability flag.
+    @retval true if NULL can be assigned temporary to the Field.
+    @retval false if NULL can not be assigned even temporary to the Field.
+  */
+  bool is_tmp_nullable() const
+  { return m_is_tmp_nullable; }
+
+  /**
+    @return whether Field has temporary value NULL.
+    @retval true if the Field has temporary value NULL.
+    @retval false if the Field's value is NOT NULL, or if the temporary
+    NULL-ability flag is reset.
+  */
+  bool is_tmp_null() const
+  { return is_tmp_nullable() && m_is_tmp_null; }
 
   /* Store functions returns 1 on overflow and -1 on fatal error */
   virtual type_conversion_status store(const char *to, uint length,
@@ -673,7 +766,7 @@ public:
   static Item_result result_merge_type(enum_field_types);
   virtual bool eq(Field *field)
   {
-    return (ptr == field->ptr && null_ptr == field->null_ptr &&
+    return (ptr == field->ptr && m_null_ptr == field->m_null_ptr &&
             null_bit == field->null_bit && field->type() == type());
   }
   virtual bool eq_def(Field *field);
@@ -776,20 +869,13 @@ public:
     tm.tv_usec= 0;
     store_timestamp(&tm);
   }
+
   virtual void set_default()
   {
     if (has_insert_default_function())
-    {
       evaluate_insert_default_function();
-      return;
-    }
-
-    my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values -
-					  table->record[0]);
-    memcpy(ptr, ptr + l_offset, pack_length());
-    if (real_maybe_null())
-      *null_ptr= ((*null_ptr & (uchar) ~null_bit) |
-		  (null_ptr[l_offset] & null_bit));
+    else
+      copy_data(table->default_values_offset());
   }
 
 
@@ -869,6 +955,12 @@ public:
   bool is_temporal_with_date_and_time() const
   { return is_temporal_type_with_date_and_time(type()); }
 
+  /**
+    Check whether the full table's row is NULL or the Field has value NULL.
+
+    @return    true if the full table's row is NULL or the Field has value NULL
+               false if neither table's row nor the Field has value NULL
+  */
   bool is_null(my_ptrdiff_t row_offset= 0) const
   {
     /*
@@ -879,47 +971,82 @@ public:
       this is the case (in which TABLE::null_row is true), the field
       is considered to be NULL.
 
-      Otherwise, if the field is NULLable, it has a valid null_ptr
+      Otherwise, if the field is NULLable, it has a valid m_null_ptr
       pointer, and its NULLity is recorded in the "null_bit" bit of
-      null_ptr[row_offset].
+      m_null_ptr[row_offset].
     */
-    return table->null_row ? true : is_real_null(row_offset);
+    return table->null_row ?
+           true :
+           is_real_null(row_offset);
   }
 
-  bool is_real_null(my_ptrdiff_t row_offset= 0) const
-  { return real_maybe_null() ? test(null_ptr[row_offset] & null_bit) : false; }
-
-  bool is_null_in_record(const uchar *record) const
-  { return real_maybe_null() ? test(record[null_offset()] & null_bit) : false; }
+  /**
+    Check whether the Field has value NULL (temporary or actual).
 
-  void set_null(my_ptrdiff_t row_offset= 0)
+    @return   true if the Field has value NULL (temporary or actual)
+              false if the Field has value NOT NULL.
+  */
+  bool is_real_null(my_ptrdiff_t row_offset= 0) const
   {
     if (real_maybe_null())
-      null_ptr[row_offset]|= null_bit;
+      return test(m_null_ptr[row_offset] & null_bit);
+
+    if (is_tmp_nullable())
+      return m_is_tmp_null;
+
+    return false;
   }
 
-  void set_notnull(my_ptrdiff_t row_offset= 0)
+  /**
+    Check if the Field has value NULL or the record specified by argument
+    has value NULL for this Field.
+
+    @return    true if the Field has value NULL or the record has value NULL
+               for thois Field.
+  */
+  bool is_null_in_record(const uchar *record) const
   {
     if (real_maybe_null())
-      null_ptr[row_offset]&= (uchar) ~null_bit;
+      return test(record[null_offset()] & null_bit);
+
+    if (is_tmp_nullable())
+      return m_is_tmp_null;
+
+    return false;
   }
 
+  void set_null(my_ptrdiff_t row_offset= 0);
+
+  void set_notnull(my_ptrdiff_t row_offset= 0);
+
+  type_conversion_status check_constraints(int mysql_errno);
+
+  /**
+    Remember the value of THD::count_cuted_fields to handle possible
+    NOT-NULL constraint errors after BEFORE-trigger execution is finished.
+    We should save the value of THD::count_cuted_fields before starting
+    BEFORE-trigger processing since during triggers execution the
+    value of THD::count_cuted_fields could be changed.
+  */
+  void set_count_cuted_fields(enum_check_fields count_cuted_fields)
+  { m_count_cuted_fields_saved= count_cuted_fields; }
+
   bool maybe_null(void) const
   { return real_maybe_null() || table->maybe_null; }
 
   /// @return true if this field is NULL-able, false otherwise.
   bool real_maybe_null(void) const
-  { return null_ptr != 0; }
+  { return m_null_ptr != NULL; }
 
   uint null_offset(const uchar *record) const
-  { return (uint) (null_ptr - record); }
+  { return (uint) (m_null_ptr - record); }
 
   uint null_offset() const
   { return null_offset(table->record[0]); }
 
   void set_null_ptr(uchar *p_null_ptr, uint p_null_bit)
   {
-    null_ptr= p_null_ptr;
+    m_null_ptr= p_null_ptr;
     null_bit= p_null_bit;
   }
 
@@ -979,7 +1106,7 @@ public:
                                uint new_null_bit);
 
   Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr)
-  { return new_key_field(root, new_table, new_ptr, null_ptr, null_bit); }
+  { return new_key_field(root, new_table, new_ptr, m_null_ptr, null_bit); }
 
   /**
      Makes a shallow copy of the Field object.
@@ -1002,23 +1129,30 @@ public:
      @param mem_root MEM_ROOT to use for memory allocation.
      @retval NULL If memory allocation failed.
    */
-  virtual Field *clone(MEM_ROOT *mem_root) const =0;
-  inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
+  virtual Field *clone(MEM_ROOT *mem_root) const = 0;
+
+  void move_field(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg)
   {
-    ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
+    ptr= ptr_arg;
+    m_null_ptr= null_ptr_arg;
+    null_bit= null_bit_arg;
   }
-  inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; }
+
+  void move_field(uchar *ptr_arg)
+  { ptr= ptr_arg; }
+
   virtual void move_field_offset(my_ptrdiff_t ptr_diff)
   {
-    ptr=ADD_TO_PTR(ptr,ptr_diff, uchar*);
-    if (null_ptr)
-      null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*);
+    ptr= ADD_TO_PTR(ptr, ptr_diff, uchar*);
+    if (real_maybe_null())
+      m_null_ptr= ADD_TO_PTR(m_null_ptr, ptr_diff, uchar*);
   }
+
   virtual void get_image(uchar *buff, uint length, const CHARSET_INFO *cs)
-    { memcpy(buff,ptr,length); }
-  virtual void set_image(const uchar *buff,uint length,
-                         const CHARSET_INFO *cs)
-    { memcpy(ptr,buff,length); }
+  { memcpy(buff, ptr, length); }
+
+  virtual void set_image(const uchar *buff, uint length, const CHARSET_INFO *cs)
+  { memcpy(ptr, buff, length); }
 
 
   /*
@@ -1113,7 +1247,9 @@ public:
   {
     return (uint) (ptr - record);
   }
-  void copy_from_tmp(int offset);
+
+  void copy_data(my_ptrdiff_t src_record_offset);
+
   uint fill_cache_field(struct st_cache_field *copy);
   virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
   virtual bool get_time(MYSQL_TIME *ltime);
@@ -1137,8 +1273,37 @@ public:
   { return DERIVATION_IMPLICIT; }
   virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; }
   virtual void set_derivation(enum Derivation derivation_arg) { }
-  bool set_warning(Sql_condition::enum_warning_level, unsigned int code,
-                   int cuted_increment) const;
+
+  /**
+    Produce warning or note about data saved into field.
+
+    @param level            - level of message (Note/Warning/Error)
+    @param code             - error code of message to be produced
+    @param cut_increment    - whenever we should increase cut fields count
+
+    @note
+      This function won't produce warning and increase cut fields counter
+      if count_cuted_fields == CHECK_FIELD_IGNORE for current thread.
+
+      if count_cuted_fields == CHECK_FIELD_IGNORE then we ignore notes.
+      This allows us to avoid notes in optimisation, like convert_constant_item().
+
+    @retval
+      1 if count_cuted_fields == CHECK_FIELD_IGNORE and error level is not NOTE
+    @retval
+      0 otherwise
+  */
+  bool set_warning(Sql_condition::enum_warning_level level,
+                   uint code,
+                   int cut_increment)
+  {
+    return set_warning(level, code, cut_increment, NULL, NULL);
+  }
+
+  bool set_warning(Sql_condition::enum_warning_level level, uint code,
+                   int cut_increment, const char *view_db,
+                   const char *view_name);
+
   inline bool check_overflow(int op_result)
   {
     return (op_result == E_DEC_OVERFLOW);
@@ -1498,14 +1663,14 @@ class Field_longstr :public Field_str
 protected:
   type_conversion_status report_if_important_data(const char *ptr,
                                                   const char *end,
-                                                  bool count_spaces) const;
+                                                  bool count_spaces);
   type_conversion_status
     check_string_copy_error(const char *well_formed_error_pos,
                             const char *cannot_convert_error_pos,
                             const char *from_end_pos,
                             const char *end,
                             bool count_spaces,
-                            const CHARSET_INFO *cs) const;
+                            const CHARSET_INFO *cs);
 public:
   Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
                 uchar null_bit_arg, utype unireg_check_arg,

=== modified file 'sql/field_conv.cc'
--- a/sql/field_conv.cc	2012-05-29 19:18:45 +0000
+++ b/sql/field_conv.cc	2012-10-18 14:55:03 +0000
@@ -100,7 +100,7 @@ static void do_field_to_null_str(Copy_fi
 
 type_conversion_status set_field_to_null(Field *field)
 {
-  if (field->real_maybe_null())
+  if (field->real_maybe_null() || field->is_tmp_nullable())
   {
     field->set_null();
     field->reset();
@@ -149,8 +149,20 @@ set_field_to_null_with_conversions(Field
     field->reset();
     return TYPE_OK;
   }
+
   if (no_conversions)
-    return TYPE_ERR_NULL_CONSTRAINT_VIOLATION;
+  {
+    if (field->is_tmp_nullable())
+    {
+      field->set_null();
+      field->reset();
+      return TYPE_OK;
+    }
+    else
+    {
+      return TYPE_ERR_NULL_CONSTRAINT_VIOLATION;
+    }
+  }
 
   /*
     Check if this is a special type, which will get a special walue
@@ -166,7 +178,7 @@ set_field_to_null_with_conversions(Field
     Item_func_now_local::store_in(field);
     return TYPE_OK;			// Ok to set time to NULL
   }
-  
+
   // Note: we ignore any potential failure of reset() here.
   field->reset();
 
@@ -175,6 +187,14 @@ set_field_to_null_with_conversions(Field
     field->table->auto_increment_field_not_null= FALSE;
     return TYPE_OK;		        // field is set in fill_record()
   }
+
+  if (field->is_tmp_nullable())
+  {
+    field->set_null();
+    field->reset();
+    return TYPE_OK;
+  }
+
   switch (field->table->in_use->count_cuted_fields) {
   case CHECK_FIELD_WARN:
     field->set_warning(Sql_condition::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1);
@@ -550,7 +570,7 @@ void Copy_field::set(uchar *to,Field *fr
   null_row= &from->table->null_row;
   if (from->maybe_null())
   {
-    from_null_ptr=from->null_ptr;
+    from_null_ptr=from->get_null_ptr();
     from_bit=	  from->null_bit;
     to_ptr[0]=	  1;				// Null as default value
     to_null_ptr=  (uchar*) to_ptr++;
@@ -598,11 +618,11 @@ void Copy_field::set(Field *to,Field *fr
   null_row= &from->table->null_row;
   if (from->maybe_null())
   {
-    from_null_ptr=	from->null_ptr;
+    from_null_ptr=	from->get_null_ptr();
     from_bit=		from->null_bit;
     if (to_field->real_maybe_null())
     {
-      to_null_ptr=	to->null_ptr;
+      to_null_ptr=	to->get_null_ptr();
       to_bit=		to->null_bit;
       do_copy=	do_copy_null;
     }
@@ -618,7 +638,7 @@ void Copy_field::set(Field *to,Field *fr
   }
   else if (to_field->real_maybe_null())
   {
-    to_null_ptr=	to->null_ptr;
+    to_null_ptr=	to->get_null_ptr();
     to_bit=		to->null_bit;
     do_copy= do_copy_maybe_null;
   }

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2012-06-22 10:11:31 +0000
+++ b/sql/ha_ndbcluster.cc	2012-10-18 14:55:03 +0000
@@ -6197,7 +6197,7 @@ static void get_default_value(void *def_
 {
   DBUG_ASSERT(field != NULL);
 
-  my_ptrdiff_t src_offset= field->table->s->default_values - field->table->record[0];
+  my_ptrdiff_t src_offset= field->table->default_values_offset();
 
   {
     if (bitmap_is_set(field->table->read_set, field->field_index))
@@ -8578,8 +8578,7 @@ static int create_ndb_column(THD *thd,
       {
         if (!(field->flags & NO_DEFAULT_VALUE_FLAG))
         {
-          my_ptrdiff_t src_offset= field->table->s->default_values 
-            - field->table->record[0];
+          my_ptrdiff_t src_offset= field->table->default_values_offset();
           if ((! field->is_real_null(src_offset)) ||
               ((field->flags & NOT_NULL_FLAG)))
           {

=== modified file 'sql/ha_ndbcluster_cond.h'
--- a/sql/ha_ndbcluster_cond.h	2011-09-30 10:24:10 +0000
+++ b/sql/ha_ndbcluster_cond.h	2012-10-18 14:55:03 +0000
@@ -221,7 +221,7 @@ public:
       }
       my_bitmap_map *old_map=
         dbug_tmp_use_all_columns(field->table, field->table->write_set);
-      ((Item *)item)->save_in_field(field, FALSE);
+      ((Item *)item)->save_in_field(field, false);
       dbug_tmp_restore_column_map(field->table->write_set, old_map);
     }
     DBUG_VOID_RETURN;

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2012-08-07 07:01:53 +0000
+++ b/sql/item.cc	2012-10-18 14:55:03 +0000
@@ -2541,7 +2541,7 @@ adjust_max_effective_column_length(Field
 void Item_field::set_field(Field *field_par)
 {
   field=result_field=field_par;			// for easy coding with fields
-  maybe_null=field->maybe_null();
+  maybe_null= field->maybe_null() || field->is_tmp_nullable();
   decimals= field->decimals();
   table_name= *field_par->table_name;
   field_name= field_par->field_name;
@@ -7936,9 +7936,7 @@ bool Item_default_value::fix_fields(THD 
   if (def_field == NULL)
     goto error;
 
-  def_field->move_field_offset((my_ptrdiff_t)
-                               (def_field->table->s->default_values -
-                                def_field->table->record[0]));
+  def_field->move_field_offset(def_field->table->default_values_offset());
   set_field(def_field);
   return FALSE;
 
@@ -8183,7 +8181,7 @@ bool Item_trigger_field::set_value(THD *
 
   field->table->copy_blobs= true;
 
-  int err_code= item->save_in_field(field, 0);
+  int err_code= item->save_in_field(field, false);
 
   field->table->copy_blobs= copy_blobs_saved;
 

=== modified file 'sql/item.h'
--- a/sql/item.h	2012-07-10 11:59:40 +0000
+++ b/sql/item.h	2012-10-18 14:55:03 +0000
@@ -24,6 +24,7 @@
 #include "thr_malloc.h"                         /* sql_calloc */
 #include "field.h"                              /* Derivation */
 #include "sql_array.h"
+#include "sql_trigger.h"
 
 class Protocol;
 struct TABLE_LIST;
@@ -795,10 +796,13 @@ public:
   */
   virtual type_conversion_status save_in_field(Field *field,
                                                bool no_conversions);
+
   virtual void save_org_in_field(Field *field)
-  { (void) save_in_field(field, 1); }
+  { save_in_field(field, true); }
+
   virtual type_conversion_status save_safe_in_field(Field *field)
-  { return save_in_field(field, 1); }
+  { return save_in_field(field, true); }
+
   virtual bool send(Protocol *protocol, String *str);
   virtual bool eq(const Item *, bool binary_cmp) const;
   virtual Item_result result_type() const { return REAL_RESULT; }
@@ -4017,7 +4021,11 @@ public:
 
   bool set_value(THD *thd, Item **it)
   {
-    return set_value(thd, NULL, it);
+    bool ret= set_value(thd, NULL, it);
+    if (!ret)
+      bitmap_set_bit(triggers->trigger_table->fields_set_during_insert,
+                     field_idx);
+    return ret;
   }
 
 private:

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2012-07-10 11:59:40 +0000
+++ b/sql/item_cmpfunc.cc	2012-10-18 14:55:03 +0000
@@ -451,7 +451,7 @@ static bool convert_constant_item(THD *t
       orig_field_val= field->val_int();
     int rc;
     if (!(*item)->is_null() &&
-        (((rc= (*item)->save_in_field(field, 1)) == TYPE_OK) ||
+        (((rc= (*item)->save_in_field(field, true)) == TYPE_OK) ||
          rc == TYPE_NOTE_TIME_TRUNCATED)) // TS-TODO
     {
       int field_cmp= 0;

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2012-05-29 19:18:45 +0000
+++ b/sql/item_func.h	2012-10-18 14:55:03 +0000
@@ -1698,13 +1698,16 @@ public:
   virtual void print(String *str, enum_query_type query_type);
   void print_assignment(String *str, enum_query_type query_type);
   const char *func_name() const { return "set_user_var"; }
+
   type_conversion_status save_in_field(Field *field, bool no_conversions,
                                        bool can_use_result_field);
+
   type_conversion_status save_in_field(Field *field, bool no_conversions)
-  {
-    return save_in_field(field, no_conversions, 1);
-  }
-  void save_org_in_field(Field *field) { (void)save_in_field(field, 1, 0); }
+  { return save_in_field(field, no_conversions, true); }
+
+  void save_org_in_field(Field *field)
+  { save_in_field(field, true, false); }
+
   bool register_field_in_read_map(uchar *arg);
   bool set_entry(THD *thd, bool create_if_not_exists);
   void cleanup();

=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc	2012-06-20 10:37:14 +0000
+++ b/sql/item_sum.cc	2012-10-18 14:55:03 +0000
@@ -971,7 +971,7 @@ bool Aggregator_distinct::add()
       return TRUE;
 
     for (Field **field=table->field ; *field ; field++)
-      if ((*field)->is_real_null(0))
+      if ((*field)->is_real_null())
         return 0;					// Don't count NULL
 
     if (tree)
@@ -991,7 +991,7 @@ bool Aggregator_distinct::add()
   }
   else
   {
-    item_sum->get_arg(0)->save_in_field(table->field[0], FALSE);
+    item_sum->get_arg(0)->save_in_field(table->field[0], false);
     if (table->field[0]->is_null())
       return 0;
     DBUG_ASSERT(tree);
@@ -2425,7 +2425,7 @@ void Item_sum_hybrid::min_max_update_tem
   nr= args[0]->val_temporal_by_field_type();
   if (!args[0]->null_value)
   {
-    if (result_field->is_null(0))
+    if (result_field->is_null())
       old_nr= nr;
     else
     {
@@ -2436,7 +2436,7 @@ void Item_sum_hybrid::min_max_update_tem
     }
     result_field->set_notnull();
   }
-  else if (result_field->is_null(0))
+  else if (result_field->is_null())
     result_field->set_null();
   result_field->store_packed(old_nr);
 }
@@ -2467,12 +2467,12 @@ void Item_sum_hybrid::min_max_update_rea
   nr= args[0]->val_real();
   if (!args[0]->null_value)
   {
-    if (result_field->is_null(0) ||
+    if (result_field->is_null() ||
 	(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
       old_nr=nr;
     result_field->set_notnull();
   }
-  else if (result_field->is_null(0))
+  else if (result_field->is_null())
     result_field->set_null();
   result_field->store(old_nr);
 }
@@ -2486,7 +2486,7 @@ void Item_sum_hybrid::min_max_update_int
   nr=args[0]->val_int();
   if (!args[0]->null_value)
   {
-    if (result_field->is_null(0))
+    if (result_field->is_null())
       old_nr=nr;
     else
     {
@@ -2499,7 +2499,7 @@ void Item_sum_hybrid::min_max_update_int
     }
     result_field->set_notnull();
   }
-  else if (result_field->is_null(0))
+  else if (result_field->is_null())
     result_field->set_null();
   result_field->store(old_nr, unsigned_flag);
 }
@@ -2517,7 +2517,7 @@ void Item_sum_hybrid::min_max_update_dec
   const my_decimal *nr= args[0]->val_decimal(&nr_val);
   if (!args[0]->null_value)
   {
-    if (result_field->is_null(0))
+    if (result_field->is_null())
       old_nr=nr;
     else
     {
@@ -2528,7 +2528,7 @@ void Item_sum_hybrid::min_max_update_dec
     }
     result_field->set_notnull();
   }
-  else if (result_field->is_null(0))
+  else if (result_field->is_null())
     result_field->set_null();
   result_field->store_decimal(old_nr);
 }

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2012-08-02 14:15:57 +0000
+++ b/sql/opt_range.cc	2012-10-18 14:55:03 +0000
@@ -6376,7 +6376,7 @@ static bool save_value_and_handle_conver
   */
 
   // Note that value may be a stored function call, executed here.
-  const type_conversion_status err= value->save_in_field_no_warnings(field, 1);
+  const type_conversion_status err= value->save_in_field_no_warnings(field, true);
   field->table->in_use->variables.sql_mode= orig_sql_mode;
 
   switch (err) {

=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc	2012-08-03 12:40:53 +0000
+++ b/sql/partition_info.cc	2012-10-18 14:55:03 +0000
@@ -442,12 +442,12 @@ bool partition_info::set_used_partition(
 
   if (fields.elements || !values.elements)
   {
-    if (fill_record(thd, fields, values, false, &full_part_field_set))
+    if (fill_record(thd, fields, values, false, &full_part_field_set, NULL))
       goto err;
   }
   else
   {
-    if (fill_record(thd, table->field, values, false, &full_part_field_set))
+    if (fill_record(thd, table->field, values, false, &full_part_field_set, NULL))
       goto err;
   }
   DBUG_ASSERT(!table->auto_increment_field_not_null);
@@ -2654,7 +2654,7 @@ bool partition_info::fix_column_value_fu
         thd->variables.sql_mode= 0;
         save_got_warning= thd->got_warning;
         thd->got_warning= 0;
-        if (column_item->save_in_field(field, TRUE) ||
+        if (column_item->save_in_field(field, true) ||
             thd->got_warning)
         {
           my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));

=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc	2011-12-09 21:08:37 +0000
+++ b/sql/rpl_record.cc	2012-10-18 14:55:03 +0000
@@ -67,7 +67,7 @@ pack_row(TABLE *table, MY_BITMAP const* 
   uchar *pack_ptr = row_data + null_byte_count;
   uchar *null_ptr = row_data;
   my_ptrdiff_t const rec_offset= record - table->record[0];
-  my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
+  my_ptrdiff_t const def_offset= table->default_values_offset();
 
   DBUG_ENTER("pack_row");
 

=== modified file 'sql/rpl_record_old.cc'
--- a/sql/rpl_record_old.cc	2011-09-07 10:08:09 +0000
+++ b/sql/rpl_record_old.cc	2012-10-18 14:55:03 +0000
@@ -28,7 +28,7 @@ pack_row_old(TABLE *table, MY_BITMAP con
   uchar *ptr;
   uint i;
   my_ptrdiff_t const rec_offset= record - table->record[0];
-  my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
+  my_ptrdiff_t const def_offset= table->default_values_offset();
   memcpy(row_data, record, n_null_bytes);
   ptr= row_data+n_null_bytes;
 

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2012-07-02 05:46:13 +0000
+++ b/sql/sp.cc	2012-10-18 14:55:03 +0000
@@ -2679,7 +2679,7 @@ bool sp_eval_expr(THD *thd, Field *resul
 
   /* Save the value in the field. Convert the value if needed. */
 
-  expr_item->save_in_field(result_field, 0);
+  expr_item->save_in_field(result_field, false);
 
   thd->count_cuted_fields= save_count_cuted_fields;
   thd->abort_on_warning= save_abort_on_warning;

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2012-07-25 10:35:49 +0000
+++ b/sql/sql_base.cc	2012-10-18 14:55:03 +0000
@@ -8816,12 +8816,13 @@ err_no_arena:
 /*
   Fill fields with given items.
 
-  @param thd           thread handler
-  @param fields        Item_fields list to be filled
-  @param values        values to fill with
-  @param ignore_errors TRUE if we should ignore errors
-  @param bitmap        Bitmap over fields to fill
-
+  @param thd                        thread handler
+  @param fields                     Item_fields list to be filled
+  @param values                     values to fill with
+  @param ignore_errors              TRUE if we should ignore errors
+  @param bitmap                     Bitmap over fields to fill
+  @param insert_into_fields_bitmap  Bitmap for fields that is set
+                                    in fill_record
   @note fill_record() may set table->auto_increment_field_not_null and a
   caller should make sure that it is reset after their last call to this
   function.
@@ -8833,7 +8834,8 @@ err_no_arena:
 
 bool
 fill_record(THD * thd, List<Item> &fields, List<Item> &values,
-            bool ignore_errors, MY_BITMAP *bitmap)
+            bool ignore_errors, MY_BITMAP *bitmap,
+            MY_BITMAP *insert_into_fields_bitmap)
 {
   List_iterator_fast<Item> f(fields),v(values);
   Item *value, *fld;
@@ -8876,11 +8878,14 @@ fill_record(THD * thd, List<Item> &field
     table= rfield->table;
     if (rfield == table->next_number_field)
       table->auto_increment_field_not_null= TRUE;
-    if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
+    if ((value->save_in_field(rfield, false) < 0) && !ignore_errors)
     {
       my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
       goto err;
     }
+    bitmap_set_bit(table->fields_set_during_insert, rfield->field_index);
+    if (insert_into_fields_bitmap)
+      bitmap_set_bit(insert_into_fields_bitmap, rfield->field_index);
   }
   DBUG_RETURN(thd->is_error());
 err:
@@ -8890,49 +8895,200 @@ err:
 }
 
 
+/**
+  Check the NOT NULL constraint on all the fields of the current record.
+
+  @param thd            Thread context.
+  @param fields         Collection of fields.
+  @param ignore_errors  Flag if errors should be suppressed.
+
+  @return Error status.
+*/
+static bool check_record(THD *thd, List<Item> &fields, bool ignore_errors)
+{
+  List_iterator_fast<Item> f(fields);
+  Item *fld;
+  Item_field *field;
+
+  while ((fld= f++))
+  {
+    field= fld->field_for_view_update();
+    if (field &&
+        field->field->check_constraints(ER_BAD_NULL_ERROR) != TYPE_OK &&
+        !ignore_errors)
+    {
+      my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
+      return true;
+    }
+  }
+  return thd->is_error();
+}
+
+
+/**
+  Check the NOT NULL constraint on all the fields of the current record.
+
+  @param thd  Thread context.
+  @param ptr  Fields.
+
+  @return Error status.
+*/
+static bool check_record(THD *thd, Field **ptr)
+{
+  Field *field;
+  while ((field = *ptr++) && !thd->is_error())
+  {
+    if (field->check_constraints(ER_BAD_NULL_ERROR) != TYPE_OK)
+      return true;
+  }
+  return thd->is_error();
+}
+
+
+/**
+  Check if SQL-statement is INSERT/INSERT SELECT/REPLACE/REPLACE SELECT
+  and there is a trigger ON INSERT
+
+  @param event         event type for triggers to be invoked
+
+  @return Test result
+    @retval true    SQL-statement is
+                    INSERT/INSERT SELECT/REPLACE/REPLACE SELECT
+                    and there is a trigger ON INSERT
+    @retval false   Either SQL-statement is not
+                    INSERT/INSERT SELECT/REPLACE/REPLACE SELECT
+                    or there isn't a trigger ON INSERT
+*/
+inline bool command_invokes_insert_triggers(enum trg_event_type event,
+                                            enum_sql_command sql_command)
+{
+  return event == TRG_EVENT_INSERT &&
+        (sql_command == SQLCOM_INSERT ||
+         sql_command == SQLCOM_INSERT_SELECT ||
+         sql_command == SQLCOM_REPLACE ||
+         sql_command == SQLCOM_REPLACE_SELECT);
+}
+
+
+/**
+  Execute BEFORE INSERT trigger.
+
+  @param thd                        thread context
+  @param triggers                   object holding list of triggers
+                                    to be invoked
+  @param event                      event type for triggers to be invoked
+  @param insert_into_fields_bitmap  Bitmap for fields that is set
+                                    in fill_record
+
+  @return Operation status
+    @retval false   OK
+    @retval true    Error occurred
+*/
+inline bool call_before_insert_triggers(THD *thd,
+                                        Table_triggers_list *triggers,
+                                        enum trg_event_type event,
+                                        MY_BITMAP *insert_into_fields_bitmap)
+{
+  TABLE *tbl= triggers->trigger_table;
+
+  for (Field** f= tbl->field; *f; ++f)
+  {
+    if (((*f)->flags & NO_DEFAULT_VALUE_FLAG) &&
+        !bitmap_is_set(insert_into_fields_bitmap, (*f)->field_index))
+    {
+      (*f)->set_tmp_null();
+    }
+  }
+
+  return triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, true);
+}
+
+
 /*
   Fill fields in list with values from the list of items and invoke
   before triggers.
 
-  SYNOPSIS
-    fill_record_n_invoke_before_triggers()
-      thd           thread context
-      fields        Item_fields list to be filled
-      values        values to fill with
-      ignore_errors TRUE if we should ignore errors
-      triggers      object holding list of triggers to be invoked
-      event         event type for triggers to be invoked
+  @param thd           thread context
+  @param fields        Item_fields list to be filled
+  @param values        values to fill with
+  @param ignore_errors TRUE if we should ignore errors
+  @param triggers      object holding list of triggers to be invoked
+  @param event         event type for triggers to be invoked
 
   NOTE
     This function assumes that fields which values will be set and triggers
     to be invoked belong to the same table, and that TABLE::record[0] and
     record[1] buffers correspond to new and old versions of row respectively.
 
-  RETURN
-    FALSE   OK
-    TRUE    error occured
+  @return Operation status
+    @retval false   OK
+    @retval true    Error occurred
 */
 
 bool
 fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
                                      List<Item> &values, bool ignore_errors,
                                      Table_triggers_list *triggers,
-                                     enum trg_event_type event)
+                                     enum trg_event_type event,
+                                     int num_fields)
 {
-  return (fill_record(thd, fields, values, ignore_errors, NULL) ||
-          (triggers && triggers->process_triggers(thd, event,
-                                                 TRG_ACTION_BEFORE, TRUE)));
+  /*
+    If it's 'INSERT INTO ... ON DUPLICATE KEY UPDATE ...' statement
+    the event is TRG_EVENT_UPDATE and the SQL-command is SQLCOM_INSERT.
+  */
+
+  if (triggers)
+  {
+    bool rc;
+
+    triggers->enable_fields_temporary_nullability(thd);
+
+    if (command_invokes_insert_triggers(event, thd->lex->sql_command))
+    {
+      DBUG_ASSERT(num_fields);
+
+      MY_BITMAP insert_into_fields_bitmap;
+      bitmap_init(&insert_into_fields_bitmap, NULL, num_fields, false);
+
+      rc= fill_record(thd, fields, values, ignore_errors, NULL,
+                      &insert_into_fields_bitmap);
+
+      if (!rc)
+        rc= call_before_insert_triggers(thd, triggers, event,
+                                        &insert_into_fields_bitmap);
+
+      bitmap_free(&insert_into_fields_bitmap);
+    }
+    else
+    {
+      rc= fill_record(thd, fields, values, ignore_errors, NULL, NULL) ||
+          triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, true);
+    }
+
+    triggers->disable_fields_temporary_nullability();
+
+    return rc ||
+           check_record(thd, triggers->trigger_table->field);
+  }
+  else
+  {
+    return
+        fill_record(thd, fields, values, ignore_errors, NULL, NULL) ||
+        check_record(thd, fields, ignore_errors);
+  }
 }
 
 
 /**
   Fill field buffer with values from Field list.
 
-  @param thd           thread handler
-  @param ptr           pointer on pointer to record
-  @param values        list of fields
-  @param ignore_errors True if we should ignore errors
-  @param bitmap        Bitmap over fields to fill
+  @param thd                        thread handler
+  @param ptr                        pointer on pointer to record
+  @param values                     list of fields
+  @param ignore_errors              True if we should ignore errors
+  @param bitmap                     Bitmap over fields to fill
+  @param insert_into_fields_bitmap  Bitmap for fields that is set
+                                    in fill_record
 
   @note fill_record() may set table->auto_increment_field_not_null and a
   caller should make sure that it is reset after their last call to this
@@ -8945,7 +9101,7 @@ fill_record_n_invoke_before_triggers(THD
 
 bool
 fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors,
-            MY_BITMAP *bitmap)
+            MY_BITMAP *bitmap, MY_BITMAP *insert_into_fields_bitmap)
 {
   List_iterator_fast<Item> v(values);
   Item *value;
@@ -8975,8 +9131,16 @@ fill_record(THD *thd, Field **ptr, List<
       continue;
     if (field == table->next_number_field)
       table->auto_increment_field_not_null= TRUE;
-    if (value->save_in_field(field, 0) == TYPE_ERR_NULL_CONSTRAINT_VIOLATION)
+    if (value->save_in_field(field, false) == TYPE_ERR_NULL_CONSTRAINT_VIOLATION)
       goto err;
+    /*
+      fill_record could be called as part of multi update and therefore
+      table->fields_set_during_insert could be NULL.
+    */
+    if (table->fields_set_during_insert)
+      bitmap_set_bit(table->fields_set_during_insert, field->field_index);
+    if (insert_into_fields_bitmap)
+      bitmap_set_bit(insert_into_fields_bitmap, field->field_index);
   }
   DBUG_ASSERT(thd->is_error() || !v++);      // No extra value!
   DBUG_RETURN(thd->is_error());
@@ -9015,11 +9179,50 @@ bool
 fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
                                      List<Item> &values, bool ignore_errors,
                                      Table_triggers_list *triggers,
-                                     enum trg_event_type event)
+                                     enum trg_event_type event,
+                                     int num_fields)
 {
-  return (fill_record(thd, ptr, values, ignore_errors, NULL) ||
-          (triggers && triggers->process_triggers(thd, event,
-                                                 TRG_ACTION_BEFORE, TRUE)));
+  bool rc;
+
+  /*
+    If it's 'INSERT INTO ... ON DUPLICATE KEY UPDATE ...' statement
+    the event is TRG_EVENT_UPDATE and the SQL-command is SQLCOM_INSERT.
+  */
+
+  if (triggers)
+  {
+    triggers->enable_fields_temporary_nullability(thd);
+
+    if (command_invokes_insert_triggers(event, thd->lex->sql_command))
+    {
+      DBUG_ASSERT(num_fields);
+
+      MY_BITMAP insert_into_fields_bitmap;
+      bitmap_init(&insert_into_fields_bitmap, NULL, num_fields, false);
+
+      rc= fill_record(thd, ptr, values, ignore_errors, NULL,
+                      &insert_into_fields_bitmap);
+
+      if (!rc)
+        rc= call_before_insert_triggers(thd, triggers, event,
+                                        &insert_into_fields_bitmap);
+
+      bitmap_free(&insert_into_fields_bitmap);
+    }
+    else
+    {
+      rc= fill_record(thd, ptr, values, ignore_errors, NULL, NULL) ||
+          triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, true);
+    }
+    triggers->disable_fields_temporary_nullability();
+  }
+  else
+    rc= fill_record(thd, ptr, values, ignore_errors, NULL, NULL);
+
+  if (rc)
+    return true;
+
+  return check_record(thd, ptr);
 }
 
 

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2012-07-24 07:09:42 +0000
+++ b/sql/sql_base.h	2012-10-18 14:55:03 +0000
@@ -169,12 +169,14 @@ bool fill_record_n_invoke_before_trigger
                                           List<Item> &values,
                                           bool ignore_errors,
                                           Table_triggers_list *triggers,
-                                          enum trg_event_type event);
+                                          enum trg_event_type event,
+                                          int num_fields);
 bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
                                           List<Item> &values,
                                           bool ignore_errors,
                                           Table_triggers_list *triggers,
-                                          enum trg_event_type event);
+                                          enum trg_event_type event,
+                                          int num_fields);
 bool insert_fields(THD *thd, Name_resolution_context *context,
 		   const char *db_name, const char *table_name,
                    List_iterator<Item> *it, bool any_privileges);
@@ -184,9 +186,11 @@ bool setup_fields(THD *thd, Ref_ptr_arra
                   List<Item> &item, enum_mark_columns mark_used_columns,
                   List<Item> *sum_func_list, bool allow_sum_func);
 bool fill_record(THD * thd, List<Item> &fields, List<Item> &values,
-                 bool ignore_errors, MY_BITMAP *bitmap);
+                 bool ignore_errors, MY_BITMAP *bitmap,
+                 MY_BITMAP *insert_into_fields_bitmap);
 bool fill_record(THD *thd, Field **field, List<Item> &values,
-                 bool ignore_errors, MY_BITMAP *bitmap);
+                 bool ignore_errors, MY_BITMAP *bitmap,
+                 MY_BITMAP *insert_into_fields_bitmap);
 
 Field *
 find_field_in_tables(THD *thd, Item_ident *item,

=== modified file 'sql/sql_executor.cc'
--- a/sql/sql_executor.cc	2012-08-03 12:40:53 +0000
+++ b/sql/sql_executor.cc	2012-10-18 14:55:03 +0000
@@ -614,7 +614,7 @@ end_sj_materialize(JOIN *join, JOIN_TAB 
       if (item->is_null())
         DBUG_RETURN(NESTED_LOOP_OK);
     }
-    fill_record(thd, table->field, sjm->table_cols, 1, NULL);
+    fill_record(thd, table->field, sjm->table_cols, 1, NULL, NULL);
     if (thd->is_error())
       DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
     if ((error= table->file->ha_write_row(table->record[0])))

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2012-07-10 16:09:50 +0000
+++ b/sql/sql_handler.cc	2012-10-18 14:55:03 +0000
@@ -761,7 +761,7 @@ retry:
 	  goto err;
         }
         old_map= dbug_tmp_use_all_columns(table, table->write_set);
-	(void) item->save_in_field(key_part->field, 1);
+	item->save_in_field(key_part->field, true);
         dbug_tmp_restore_column_map(table->write_set, old_map);
 	key_len+=key_part->store_length;
         keypart_map= (keypart_map << 1) | 1;

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2012-08-03 11:31:19 +0000
+++ b/sql/sql_insert.cc	2012-10-18 14:55:03 +0000
@@ -610,6 +610,35 @@ create_insert_stmt_from_insert_delayed(T
 
 
 /**
+   Wrapper for invocation of function check_that_all_fields_are_given_value.
+
+   @param[in] thd               Thread handler
+   @param[in] table             Table to insert into
+   @param[in] table_list        Table list
+   @param[in] abort_on_warning  Whether to report an error or a warning
+                                if some INSERT field is not assigned.
+
+  @return Operation status.
+    @retval false   Success
+    @retval true    Failure
+ */
+static bool safely_check_that_all_fields_are_given_values(
+  THD* thd, TABLE* table,
+  TABLE_LIST* table_list,
+  bool abort_on_warning)
+{
+  bool saved_abort_on_warning= thd->abort_on_warning;
+  thd->abort_on_warning= abort_on_warning;
+
+  bool res= check_that_all_fields_are_given_values(thd, table, table_list);
+
+  thd->abort_on_warning= saved_abort_on_warning;
+
+  return res;
+}
+
+
+/**
   INSERT statement implementation
 
   @note Like implementations of other DDL/DML in MySQL, this function
@@ -670,6 +699,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
   MY_BITMAP used_partitions;
   bool prune_needs_default_values;
 #endif /* WITH_PARITITION_STORAGE_ENGINE */
+
   DBUG_ENTER("mysql_insert");
 
   /*
@@ -725,7 +755,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 
   /* mysql_prepare_insert set table_list->table if it was not set */
   table= table_list->table;
-
   /* Must be done before can_prune_insert, due to internal initialization. */
   if (info.add_function_default_columns(table, table->write_set))
     goto exit_without_my_ok;
@@ -925,7 +954,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
   {
     if (duplic != DUP_ERROR || ignore)
       table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
-    /**
+    /*
       This is a simple check for the case when the table has a trigger
       that reads from it, or when the statement invokes a stored function
       that reads from the table being inserted to.
@@ -940,19 +969,25 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 
   prepare_triggers_for_insert_stmt(table);
 
-
   if (table_list->prepare_where(thd, 0, TRUE) ||
       table_list->prepare_check_option(thd))
     error= 1;
 
+  for (Field** next_field= table->field; *next_field; ++next_field)
+  {
+    (*next_field)->reset_warnings();
+  }
+
   while ((values= its++))
   {
     if (fields.elements || !value_count)
     {
       restore_record(table,s->default_values);	// Get empty record
+
       if (fill_record_n_invoke_before_triggers(thd, fields, *values, 0,
                                                table->triggers,
-                                               TRG_EVENT_INSERT))
+                                               TRG_EVENT_INSERT,
+                                               table->s->fields))
       {
 	if (values_list.elements != 1 && ! thd->is_error())
 	{
@@ -967,6 +1002,23 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 	error=1;
 	break;
       }
+
+      res= safely_check_that_all_fields_are_given_values(
+        thd,
+        table ? table : context->table_list->table,
+        context->table_list,
+        !ignore && thd->is_strict_mode());
+
+      if (res)
+      {
+        if (values_list.elements != 1 && !thd->is_error())
+        {
+          info.stats.records++;
+          continue;
+        }
+        error= 1;
+        break;
+      }
     }
     else
     {
@@ -992,7 +1044,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       }
       if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0,
                                                table->triggers,
-                                               TRG_EVENT_INSERT))
+                                               TRG_EVENT_INSERT,
+                                               table->s->fields))
       {
 	if (values_list.elements != 1 && ! thd->is_error())
 	{
@@ -1032,6 +1085,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
     thd->get_stmt_da()->inc_current_row_for_warning();
   }
 
+  error= thd->get_stmt_da()->is_error();
   free_underlaid_joins(thd, &thd->lex->select_lex);
   joins_freed= TRUE;
 
@@ -1167,6 +1221,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 
   if (error)
     goto exit_without_my_ok;
+
   if (values_list.elements == 1 && (!(thd->variables.option_bits & OPTION_WARNINGS) ||
 				    !thd->cuted_fields))
   {
@@ -1484,21 +1539,9 @@ bool mysql_prepare_insert(THD *thd, TABL
                        *values, MARK_COLUMNS_READ, 0, 0) ||
           check_insert_fields(thd, context->table_list, fields, *values,
                               !insert_into_view, 0, &map));
-
-    if (!res && check_fields)
-    {
-      bool saved_abort_on_warning= thd->abort_on_warning;
-      thd->abort_on_warning= abort_on_warning;
-      res= check_that_all_fields_are_given_values(thd, 
-                                                  table ? table : 
-                                                  context->table_list->table,
-                                                  context->table_list);
-      thd->abort_on_warning= saved_abort_on_warning;
-    }
-
-   if (!res)
-     res= setup_fields(thd, Ref_ptr_array(),
-                       update_values, MARK_COLUMNS_READ, 0, 0);
+    if (!res)
+      res= setup_fields(thd, Ref_ptr_array(),
+                        update_values, MARK_COLUMNS_READ, 0, 0);
 
     if (!res && duplic == DUP_UPDATE)
     {
@@ -1712,7 +1755,7 @@ int write_record(THD *thd, TABLE *table,
                                                  *update->update_values,
                                                  ignore_errors,
                                                  table->triggers,
-                                                 TRG_EVENT_UPDATE))
+                                                 TRG_EVENT_UPDATE, 0))
           goto before_trg_err;
 
         /* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
@@ -1896,7 +1939,7 @@ int check_that_all_fields_are_given_valu
                                            TABLE_LIST *table_list)
 {
   int err= 0;
-  MY_BITMAP *write_set= entry->write_set;
+  MY_BITMAP *write_set= entry->fields_set_during_insert;
 
   for (Field **field=entry->field ; *field ; field++)
   {
@@ -1911,20 +1954,13 @@ int check_that_all_fields_are_given_valu
         view= test(table_list->view);
       }
       if (view)
-      {
-        push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
-                            ER_NO_DEFAULT_FOR_VIEW_FIELD,
-                            ER(ER_NO_DEFAULT_FOR_VIEW_FIELD),
-                            table_list->view_db.str,
-                            table_list->view_name.str);
-      }
+        (*field)->set_warning(Sql_condition::WARN_LEVEL_WARN,
+                              ER_NO_DEFAULT_FOR_VIEW_FIELD, 1,
+                              table_list->view_db.str,
+                              table_list->view_name.str);
       else
-      {
-        push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
-                            ER_NO_DEFAULT_FOR_FIELD,
-                            ER(ER_NO_DEFAULT_FOR_FIELD),
-                            (*field)->field_name);
-      }
+        (*field)->set_warning(Sql_condition::WARN_LEVEL_WARN,
+                              ER_NO_DEFAULT_FOR_FIELD, 1);
       err= 1;
     }
   }
@@ -3407,17 +3443,6 @@ select_insert::prepare(List<Item> &value
         check_insert_fields(thd, table_list, *fields, values,
                             !insert_into_view, 1, &map));
 
-  if (!res && fields->elements)
-  {
-    bool saved_abort_on_warning= thd->abort_on_warning;
-
-    thd->abort_on_warning= !ignore_errors && thd->is_strict_mode();
-
-    res= check_that_all_fields_are_given_values(thd, table_list->table, 
-                                                table_list);
-    thd->abort_on_warning= saved_abort_on_warning;
-  }
-
   if (duplicate_handling == DUP_UPDATE && !res)
   {
     Name_resolution_context *context= &lex->select_lex.context;
@@ -3532,7 +3557,15 @@ select_insert::prepare(List<Item> &value
         table_list->prepare_check_option(thd));
 
   if (!res)
+  {
      prepare_triggers_for_insert_stmt(table);
+  }
+
+  for (Field** next_field= table->field; *next_field; ++next_field)
+  {
+    (*next_field)->reset_warnings();
+    (*next_field)->reset_tmp_null();
+  }
 
   DBUG_RETURN(res);
 }
@@ -3656,16 +3689,19 @@ bool select_insert::send_data(List<Item>
   DBUG_RETURN(error);
 }
 
-
 void select_insert::store_values(List<Item> &values)
 {
   const bool ignore_err= true;
   if (fields->elements)
     fill_record_n_invoke_before_triggers(thd, *fields, values, ignore_err,
-                                         table->triggers, TRG_EVENT_INSERT);
+                                         table->triggers, TRG_EVENT_INSERT,
+                                         table->s->fields);
   else
     fill_record_n_invoke_before_triggers(thd, table->field, values, ignore_err,
-                                         table->triggers, TRG_EVENT_INSERT);
+                                         table->triggers, TRG_EVENT_INSERT,
+                                         table->s->fields);
+
+  check_that_all_fields_are_given_values(thd, table_list->table, table_list);
 }
 
 void select_insert::send_error(uint errcode,const char *err)
@@ -3739,6 +3775,16 @@ bool select_insert::send_eof()
     table->file->print_error(error,MYF(0));
     DBUG_RETURN(1);
   }
+
+  /*
+    For the strict_mode call of push_warning above results to set
+    error in Diagnostic_area. Therefore it is necessary to check whether
+    the error was set and leave method if it is true. If we didn't do
+    so we would failed later when my_ok is called.
+  */
+  if (thd->get_stmt_da()->is_error())
+    DBUG_RETURN(true);
+
   char buff[160];
   if (info.get_ignore_errors())
     my_snprintf(buff, sizeof(buff),
@@ -4145,12 +4191,19 @@ select_create::prepare2()
   }
   /* Mark all fields that are given values */
   for (Field **f= field ; *f ; f++)
+  {
     bitmap_set_bit(table->write_set, (*f)->field_index);
+    bitmap_set_bit(table->fields_set_during_insert, (*f)->field_index);
+  }
 
   // Set up an empty bitmap of function defaults
   if (info.add_function_default_columns(table, table->write_set))
     DBUG_RETURN(1);
 
+  if (info.add_function_default_columns(table,
+                                        table->fields_set_during_insert))
+    DBUG_RETURN(1);
+
   table->next_number_field=table->found_next_number_field;
 
   restore_record(table,s->default_values);      // Get empty record
@@ -4169,8 +4222,15 @@ select_create::prepare2()
   if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
     table->file->ha_start_bulk_insert((ha_rows) 0);
   thd->abort_on_warning= (!ignore_errors && thd->is_strict_mode());
+
+  enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
+  thd->count_cuted_fields= CHECK_FIELD_WARN;
+
   if (check_that_all_fields_are_given_values(thd, table, table_list))
     DBUG_RETURN(1);
+
+  thd->count_cuted_fields= save_count_cuted_fields;
+
   table->mark_columns_needed_for_insert();
   table->file->extra(HA_EXTRA_WRITE_CACHE);
   DBUG_RETURN(0);
@@ -4229,7 +4289,8 @@ void select_create::store_values(List<It
 {
   const bool ignore_err= true;
   fill_record_n_invoke_before_triggers(thd, field, values, ignore_err,
-                                       table->triggers, TRG_EVENT_INSERT);
+                                       table->triggers, TRG_EVENT_INSERT,
+                                       table->s->fields);
 }
 
 

=== modified file 'sql/sql_insert.h'
--- a/sql/sql_insert.h	2012-05-29 12:52:32 +0000
+++ b/sql/sql_insert.h	2012-10-18 14:55:03 +0000
@@ -35,6 +35,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type,
                                   enum_duplicates duplic,
                                   bool is_multi_insert);
+
 int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
                                            TABLE_LIST *table_list);
 void prepare_triggers_for_insert_stmt(TABLE *table);

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2012-04-10 20:17:48 +0000
+++ b/sql/sql_load.cc	2012-10-18 14:55:03 +0000
@@ -264,6 +264,10 @@ int mysql_load(THD *thd,sql_exchange *ex
   }
 
   table= table_list->table;
+
+  for (Field **cur_field= table->field; *cur_field; ++cur_field)
+    (*cur_field)->reset_warnings();
+
   transactional_table= table->file->has_transactions();
 #ifndef EMBEDDED_LIBRARY
   is_concurrent= (table_list->lock_type == TL_WRITE_CONCURRENT_INSERT);
@@ -881,7 +885,8 @@ read_fixed_length(THD *thd, COPY_INFO &i
         fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
                                              ignore_check_option_errors,
                                              table->triggers,
-                                             TRG_EVENT_INSERT))
+                                             TRG_EVENT_INSERT,
+                                             table->s->fields))
       DBUG_RETURN(1);
 
     switch (table_list->view_check_option(thd,
@@ -964,6 +969,13 @@ read_sep_field(THD *thd, COPY_INFO &info
 
       real_item= item->real_item();
 
+      /*
+        Enable temporary nullability for items that corresponds
+        to table fields.
+      */
+      if (real_item->type() == Item::FIELD_ITEM)
+        ((Item_field *)real_item)->field->set_tmp_nullable();
+
       if ((!read_info.enclosed &&
 	  (enclosed_length && length == 4 &&
            !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
@@ -979,18 +991,19 @@ read_sep_field(THD *thd, COPY_INFO &info
                      thd->get_stmt_da()->current_row_for_warning());
             DBUG_RETURN(1);
           }
-          // Try to set to NULL; if it fails, field remains at 0.
-          field->set_null();
-          if (!field->maybe_null())
+          if (!field->real_maybe_null() &&
+              field->type() == FIELD_TYPE_TIMESTAMP)
           {
-            if (field->type() == FIELD_TYPE_TIMESTAMP)
-            {
-              // Specific of TIMESTAMP NOT NULL: set to CURRENT_TIMESTAMP.
-              Item_func_now_local::store_in(field);
-            }
-            else if (field != table->next_number_field)
-              field->set_warning(Sql_condition::WARN_LEVEL_WARN,
-                                 ER_WARN_NULL_TO_NOTNULL, 1);
+            // Specific of TIMESTAMP NOT NULL: set to CURRENT_TIMESTAMP.
+            Item_func_now_local::store_in(field);
+          }
+          else
+          {
+            /*
+              Set field to NULL. Later we will clear temporary nullability flag
+              and check NOT NULL constraint.
+            */
+            field->set_null();
           }
 	}
         else if (item->type() == Item::STRING_ITEM)
@@ -1087,11 +1100,46 @@ read_sep_field(THD *thd, COPY_INFO &info
       }
     }
 
+    // Clear temporary nullability flags for every field in the table.
+
+    it.rewind();
+    while ((item= it++))
+    {
+      Item *real_item= item->real_item();
+      if (real_item->type() == Item::FIELD_ITEM)
+        ((Item_field *)real_item)->field->reset_tmp_nullable();
+    }
+
     if (thd->killed ||
         fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
                                              ignore_check_option_errors,
                                              table->triggers,
-                                             TRG_EVENT_INSERT))
+                                             TRG_EVENT_INSERT,
+                                             table->s->fields))
+      DBUG_RETURN(1);
+
+    if (!table->triggers)
+    {
+      /*
+        If there is no trigger for the table then check the NOT NULL constraint
+        for every table field.
+
+        For the table that has BEFORE-INSERT trigger installed checking for
+        NOT NULL constraint is done inside function
+        fill_record_n_invoke_before_triggers() after all trigger instructions
+        has been executed.
+      */
+      it.rewind();
+
+      while ((item= it++))
+      {
+        Item *real_item= item->real_item();
+        if (real_item->type() == Item::FIELD_ITEM)
+          ((Item_field *) real_item)->field->check_constraints(ER_WARN_NULL_TO_NOTNULL);
+      }
+    }
+
+    if (thd->is_error())
       DBUG_RETURN(1);
 
     switch (table_list->view_check_option(thd,
@@ -1265,7 +1313,8 @@ read_xml_field(THD *thd, COPY_INFO &info
         fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
                                              ignore_check_option_errors,
                                              table->triggers,
-                                             TRG_EVENT_INSERT))
+                                             TRG_EVENT_INSERT,
+                                             table->s->fields))
       DBUG_RETURN(1);
 
     switch (table_list->view_check_option(thd,

=== modified file 'sql/sql_tmp_table.cc'
--- a/sql/sql_tmp_table.cc	2012-08-03 11:41:36 +0000
+++ b/sql/sql_tmp_table.cc	2012-10-18 14:55:03 +0000
@@ -918,11 +918,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARA
          inherit the default value that is defined for the field referred
          by the Item_field object from which 'field' has been created.
       */
-      my_ptrdiff_t diff;
       Field *orig_field= default_field[i];
       /* Get the value from default_values */
-      diff= (my_ptrdiff_t) (orig_field->table->s->default_values-
-                            orig_field->table->record[0]);
+      my_ptrdiff_t diff= orig_field->table->default_values_offset();
       orig_field->move_field_offset(diff);      // Points now at default_values
       if (orig_field->is_real_null())
         field->set_null();

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2012-07-24 07:09:42 +0000
+++ b/sql/sql_trigger.cc	2012-10-18 14:55:03 +0000
@@ -2242,6 +2242,47 @@ bool Table_triggers_list::is_fields_upda
 
 
 /**
+  Mark all trigger fields as "temporary nullable" and remember the current
+  THD::count_cuted_fields value.
+
+  @param thd Thread context.
+*/
+void Table_triggers_list::enable_fields_temporary_nullability(THD* thd)
+{
+  for (Field** next_field= trigger_table->field; *next_field; ++next_field)
+  {
+    (*next_field)->set_tmp_nullable();
+    (*next_field)->set_count_cuted_fields(thd->count_cuted_fields);
+
+    /*
+      For statement LOAD INFILE we set field values during parsing of data file
+      and later run fill_record_n_invoke_before_triggers() to invoke table's
+      triggers. fill_record_n_invoke_before_triggers() calls this method
+      to enable temporary nullability before running trigger's instructions
+      Since for the case of handling statement LOAD INFILE the null value of
+      fields have been already set we don't have to reset these ones here.
+      In case of handling statements INSERT/REPLACE/INSERT SELECT/
+      REPLACE SELECT we set field's values inside method fill_record
+      that is called from fill_record_n_invoke_before_triggers()
+      after the method enable_fields_temporary_nullability has been executed.
+    */
+    if (thd->lex->sql_command != SQLCOM_LOAD)
+      (*next_field)->reset_tmp_null();
+  }
+}
+
+
+/**
+  Reset "temporary nullable" flag from trigger fields.
+*/
+void Table_triggers_list::disable_fields_temporary_nullability()
+{
+  for (Field** next_field= trigger_table->field; *next_field; ++next_field)
+    (*next_field)->reset_tmp_nullable();
+}
+
+
+/**
   Mark fields of subject table which we read/set in its triggers
   as such.
 

=== modified file 'sql/sql_trigger.h'
--- a/sql/sql_trigger.h	2012-05-29 22:14:39 +0000
+++ b/sql/sql_trigger.h	2012-10-18 14:55:03 +0000
@@ -213,6 +213,10 @@ public:
   bool is_fields_updated_in_trigger(MY_BITMAP *used_fields,
                                     trg_event_type event_type,
                                     trg_action_time_type action_time);
+
+  void enable_fields_temporary_nullability(THD* thd);
+  void disable_fields_temporary_nullability();
+
 private:
   bool prepare_record1_accessors();
   LEX_STRING* change_table_name_in_trignames(const char *old_db_name,

=== modified file 'sql/sql_union.cc'
--- a/sql/sql_union.cc	2012-08-03 11:41:36 +0000
+++ b/sql/sql_union.cc	2012-10-18 14:55:03 +0000
@@ -90,7 +90,7 @@ bool select_union::send_data(List<Item> 
     unit->offset_limit_cnt--;
     return 0;
   }
-  fill_record(thd, table->field, values, 1, NULL);
+  fill_record(thd, table->field, values, 1, NULL, NULL);
   if (thd->is_error())
     return 1;
 

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2012-07-20 07:15:25 +0000
+++ b/sql/sql_update.cc	2012-10-18 14:55:03 +0000
@@ -253,7 +253,7 @@ static void prepare_record_for_error_mes
   /* Copy the newly read columns into the new record. */
   for (field_p= table->field; (field= *field_p); field_p++)
     if (bitmap_is_set(&unique_map, field->field_index))
-      field->copy_from_tmp(table->s->rec_buff_length);
+      field->copy_data(table->s->rec_buff_length);
 
   DBUG_VOID_RETURN;
 }
@@ -809,7 +809,7 @@ int mysql_update(THD *thd,
       store_record(table,record[1]);
       if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
                                                table->triggers,
-                                               TRG_EVENT_UPDATE))
+                                               TRG_EVENT_UPDATE, 0))
         break; /* purecov: inspected */
 
       found++;
@@ -2086,7 +2086,7 @@ bool multi_update::send_data(List<Item> 
                                                *values_for_table[offset],
                                                false, // ignore_errors
                                                table->triggers,
-                                               TRG_EVENT_UPDATE))
+                                               TRG_EVENT_UPDATE, 0))
 	DBUG_RETURN(1);
 
       /*
@@ -2188,10 +2188,19 @@ bool multi_update::send_data(List<Item> 
         field_num++;
       } while ((tbl= tbl_it++));
 
+      /*
+        Enable temporary nullability for temporary table fields.
+      */
+      for (Field** modified_fields= tmp_table->field + 1 + unupdated_check_opt_tables.elements;
+           *modified_fields; ++modified_fields)
+      {
+        (*modified_fields)->set_tmp_nullable();
+      }
+
       /* Store regular updated fields in the row. */
       fill_record(thd,
                   tmp_table->field + 1 + unupdated_check_opt_tables.elements,
-                  *values_for_table[offset], 1, NULL);
+                  *values_for_table[offset], 1, NULL, NULL);
 
       /* Write row, ignoring duplicated updates to a row */
       error= tmp_table->file->ha_write_row(tmp_table->record[0]);

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2012-07-24 07:09:42 +0000
+++ b/sql/table.cc	2012-10-18 14:55:03 +0000
@@ -2141,7 +2141,7 @@ partititon_err:
   /* Allocate bitmaps */
 
   bitmap_size= share->column_bitmap_size;
-  if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size*3)))
+  if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size * 4)))
     goto err;
   bitmap_init(&outparam->def_read_set,
               (my_bitmap_map*) bitmaps, share->fields, FALSE);
@@ -2149,6 +2149,9 @@ partititon_err:
               (my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE);
   bitmap_init(&outparam->tmp_set,
               (my_bitmap_map*) (bitmaps+bitmap_size*2), share->fields, FALSE);
+  bitmap_init(&outparam->def_fields_set_during_insert,
+              (my_bitmap_map*) (bitmaps + bitmap_size * 3), share->fields,
+              FALSE);
   outparam->default_column_bitmaps();
 
   /* The table struct is now initialized;  Open the table */
@@ -4933,6 +4936,9 @@ void TABLE::clear_column_bitmaps()
   */
   memset(def_read_set.bitmap, 0, s->column_bitmap_size*2);
   column_bitmaps_set(&def_read_set, &def_write_set);
+
+  bitmap_clear_all(&def_fields_set_during_insert);
+  fields_set_during_insert= &def_fields_set_during_insert;
 }
 
 

=== modified file 'sql/table.h'
--- a/sql/table.h	2012-07-24 07:09:42 +0000
+++ b/sql/table.h	2012-10-18 14:55:03 +0000
@@ -1047,7 +1047,14 @@ public:
   uchar		*null_flags;
   my_bitmap_map	*bitmap_init_value;
   MY_BITMAP     def_read_set, def_write_set, tmp_set; /* containers */
+  /*
+    the data member def_fields_set_during_insert is used to initialize
+    bitmap without allocation of memory on MEM_ROOT.
+    fields_set_during_insert is set as a pointer to this data member.
+  */
+  MY_BITMAP     def_fields_set_during_insert;
   MY_BITMAP     *read_set, *write_set;          /* Active column sets */
+  MY_BITMAP     *fields_set_during_insert;
   /*
    The ID of the query that opened and is using this table. Has different
    meanings depending on the table type.
@@ -1244,6 +1251,9 @@ public:
   bool update_const_key_parts(Item *conds);
 
   bool check_read_removal(uint index);
+
+  my_ptrdiff_t default_values_offset() const
+  { return (my_ptrdiff_t) (s->default_values - record[0]); }
 };
 
 

=== modified file 'sql/unireg.cc'
--- a/sql/unireg.cc	2012-06-22 10:11:31 +0000
+++ b/sql/unireg.cc	2012-10-18 14:55:03 +0000
@@ -1133,7 +1133,7 @@ static bool make_empty_rec(THD *thd, Fil
         be constant.
       */
       DBUG_ASSERT(field->def->type() != Item::FUNC_ITEM);
-      type_conversion_status res= field->def->save_in_field(regfield, 1);
+      type_conversion_status res= field->def->save_in_field(regfield, true);
       if (res != TYPE_OK && res != TYPE_NOTE_TIME_TRUNCATED &&
           res != TYPE_NOTE_TRUNCATED)
       {

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2012-07-26 18:46:34 +0000
+++ b/tests/mysql_client_test.c	2012-10-18 14:55:03 +0000
@@ -7847,7 +7847,7 @@ static void test_cuted_rows()
   count= mysql_warning_count(mysql);
   if (!opt_silent)
     fprintf(stdout, "\n total warnings: %d", count);
-  DIE_UNLESS(count == 2);
+  DIE_UNLESS(count == 1);
 
   rc= mysql_query(mysql, "SHOW WARNINGS");
   myquery(rc);
@@ -7856,7 +7856,7 @@ static void test_cuted_rows()
   mytest(result);
 
   rc= my_process_result_set(result);
-  DIE_UNLESS(rc == 2);
+  DIE_UNLESS(rc == 1);
   mysql_free_result(result);
 
   rc= mysql_query(mysql, "INSERT INTO t1 VALUES('junk'), (876789)");

=== modified file 'unittest/gunit/field_date-t.cc'
--- a/unittest/gunit/field_date-t.cc	2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/field_date-t.cc	2012-10-18 14:55:03 +0000
@@ -73,9 +73,9 @@ private:
   void initialize()
   {
     ptr= buffer;
-    null_ptr= &null_byte;
     memset(buffer, 0, PACK_LENGTH);
     null_byte= '\0';
+    set_null_ptr(&null_byte, 1);
   }
 public:
 

=== modified file 'unittest/gunit/field_datetime-t.cc'
--- a/unittest/gunit/field_datetime-t.cc	2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/field_datetime-t.cc	2012-10-18 14:55:03 +0000
@@ -51,9 +51,9 @@ private:
   void initialize()
   {
     ptr= buffer;
-    null_ptr= &null_byte;
     memset(buffer, 0, PACK_LENGTH);
     null_byte= '\0';
+    set_null_ptr(&null_byte, 1);
   }
 
 public:

=== modified file 'unittest/gunit/field_long-t.cc'
--- a/unittest/gunit/field_long-t.cc	2012-06-24 07:07:58 +0000
+++ b/unittest/gunit/field_long-t.cc	2012-10-18 14:55:03 +0000
@@ -47,9 +47,9 @@ class Mock_field_long : public Field_lon
   void initialize()
   {
     ptr= buffer;
-    null_ptr= &null_byte;
     memset(buffer, 0, PACK_LENGTH);
     null_byte= '\0';
+    set_null_ptr(&null_byte, 1);
   }
 public:
   Mock_field_long()

=== modified file 'unittest/gunit/field_newdecimal-t.cc'
--- a/unittest/gunit/field_newdecimal-t.cc	2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/field_newdecimal-t.cc	2012-10-18 14:55:03 +0000
@@ -51,9 +51,9 @@ class Mock_field_new_decimal : public Fi
   void initialize()
   {
     ptr= buffer;
-    null_ptr= &null_byte;
     memset(buffer, 0, MAX_FIELD_WIDTH);
     null_byte= '\0';
+    set_null_ptr(&null_byte, 1);
   }
 
 public:

=== modified file 'unittest/gunit/mock_field_timestamp.h'
--- a/unittest/gunit/mock_field_timestamp.h	2012-01-31 15:16:16 +0000
+++ b/unittest/gunit/mock_field_timestamp.h	2012-10-18 14:55:03 +0000
@@ -34,7 +34,7 @@ class Mock_field_timestamp : public Fiel
     EXPECT_FALSE(table == NULL) << "Out of memory";
     ptr= buffer;
     memset(buffer, 0, PACK_LENGTH);
-    null_ptr= &null_byte;
+    set_null_ptr(&null_byte, 1);
   }
 
 public:

=== modified file 'unittest/gunit/mock_field_timestampf.h'
--- a/unittest/gunit/mock_field_timestampf.h	2012-01-31 15:16:16 +0000
+++ b/unittest/gunit/mock_field_timestampf.h	2012-10-18 14:55:03 +0000
@@ -28,7 +28,7 @@ class Mock_field_timestampf : public Fie
     EXPECT_FALSE(table == NULL) << "Out of memory";
     ptr= buffer;
     memset(buffer, 0, PACK_LENGTH);
-    null_ptr= &null_byte;
+    set_null_ptr(&null_byte, 1);
   }
 
 public:

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (Dmitry.Shulga:4183 to 4184) WL#6030Dmitry Shulga22 Oct