List:Commits« Previous MessageNext Message »
From:Jon Olav Hauglid Date:June 1 2010 1:33pm
Subject:bzr commit into mysql-next-mr-bugfixing branch (jon.hauglid:3221) Bug#6295
View as plain text  
#At file:///export/home/x/mysql-next-mr-bugfixing-bug6295/ based on revid:alik@stripped

 3221 Jon Olav Hauglid	2010-06-01
      Bug#6295 Triggers are not processed for NOT NULL columns
      
      *** This is a preliminary version of the patch. ***
      
      The problem was that BEFORE INSERT/UPDATE triggers where not executed
      until after NOT NULL had been checked. This meant that inserting NULL
      into a NOT NULL column would fail even if a BEFORE INSERT trigger
      existed that changed NULL to a valid value.
      
      This patch fixes the problem by changing the code so BEFORE INSERT/
      UPDATE triggers are run before NOT NULL is checked.
      
      For this to work, the patch also makes it so that NOT NULL Fields
      temporarily can store NULL. Before, memory would not be allocated
      for storing the presence of NULL in NOT NULL Fields.
      
      Test case added to trigger.test.
     @ include/mysql_com.h
        Added flag for fields made temporarily nullable for trigger processing.
     @ mysql-test/r/trigger.result
        Updated result file - multi-value INSERT will give warning, not error.
        Added test coverage for Bug#6295.
     @ mysql-test/t/trigger.test
        Added test coverage for Bug#6295.
     @ sql/field.cc
        Renamed maybe_null to is_nullable.
        Since NOT NULL fields now must be able to store NULL temporarily,
        we can no longer use null_ptr to check for NOT NULL. Changed Field
        constructors to have nullability as an explicit parameter.
        Added Field::check_constraints() to check if the current record
        meets the constraints (NOT NULL) of the given Field.
     @ sql/field.h
        Renamed maybe_null to is_nullable.
        Since NOT NULL fields now must be able to store NULL temporarily,
        we can no longer use null_ptr to check for NOT NULL. Changed Field
        constructors to have nullability as an explicit parameter.
        NOT NULL fields can now temporarily be made nullable using
        Field::set_temporary_nullable(bool).
        Added Field::check_constraints() to check if the current record
        meets the constraints (NOT NULL) of the given Field.
     @ sql/field_conv.cc
        Renamed maybe_null to is_nullable.
        Removed checking of NOT NULL from set_field_to_null() and
        set_field_to_null_with_conversions(). This is now done later
        after triggers have been executed.
        NOT NULL fields are now temporarily be made nullable using
        Field::set_temporary_nullable()
     @ sql/filesort.cc
        Renamed maybe_null to is_nullable.
     @ sql/ha_ndbcluster_cond.cc
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/item.cc
        Renamed maybe_null to is_nullable.
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
        NEW.columns inside triggers are made temporarily nullable.
     @ sql/item.h
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/item_cmpfunc.cc
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/item_func.h
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/item_sum.cc
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/log_event.cc
        Renamed maybe_null to is_nullable.
     @ sql/log_event_old.cc
        Renamed maybe_null to is_nullable.
     @ sql/opt_range.cc
        Renamed maybe_null to is_nullable.
     @ sql/opt_sum.cc
        Renamed maybe_null to is_nullable.
     @ sql/partition_info.cc
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/rpl_record.cc
        Renamed maybe_null to is_nullable.
     @ sql/sp_head.cc
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/sql_base.cc
        Moved checking of constraints (NOT NULL) to separate functions.
        Refactored so that triggers are executed before constraints are checked.
        Use TABLE::nullable_field for updates.
     @ sql/sql_base.h
        Added function to check if constraints are met by the current record.
     @ sql/sql_handler.cc
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/sql_insert.cc
        Allocate extra memory for temporary storage of null_bits for NOT
        NULL fields.
        Initialize TABLE_SHARE::nullable_field.
        Use TABLE::nullable_field for updates.
     @ sql/sql_load.cc
        Renamed maybe_null to is_nullable.
        Use TABLE::nullable_field for updates.
     @ sql/sql_partition.cc
        Renamed maybe_null to is_nullable.
     @ sql/sql_select.cc
        Renamed maybe_null to is_nullable.
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/sql_select.h
        Renamed maybe_null to is_nullable.
        Constraints (NOT NULL) must now be checked separately after
        save_in_field().
     @ sql/sql_show.cc
        Renamed maybe_null to is_nullable.
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
     @ sql/sql_table.cc
        Renamed maybe_null to is_nullable.
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
     @ sql/sql_trigger.cc
        Use TABLE::nullable_field for NEW.columns inside triggers.
        Check constrains (NOT NULL) on NEW.columns after the
        trigger has ben executed.
     @ sql/sql_union.cc
        Constraints (NOT NULL) must now be checked separately after
        fill_record.
     @ sql/sql_update.cc
        Constraints (NOT NULL) must now be checked separately after
        fill_record.
     @ sql/sql_view.cc
        Use TABLE::nullable_field for updates.
     @ sql/table.cc
        Renamed maybe_null to is_nullable.
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
        Allocate extra memory for temporary storage of null_bits for NOT
        NULL fields.
        Initialize TABLE_SHARE::nullable_field.
     @ sql/table.h
        Added TABLE::nullable_field to be used for updates.
     @ sql/unireg.cc
        Changed NULL assignment to use a Field function rather than 
        directly accessing Field member variables.
     @ storage/csv/ha_tina.cc
        Renamed maybe_null to is_nullable.
     @ storage/federated/ha_federated.cc
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
     @ storage/heap/ha_heap.cc
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
     @ storage/ibmdb2i/ha_ibmdb2i.cc
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
     @ storage/innobase/handler/ha_innodb.cc
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.
     @ storage/myisam/ha_myisam.cc
        Changed NOT NULL tests to use a Field function rather than 
        directly accessing Field member variables.

    modified:
      include/mysql_com.h
      mysql-test/r/trigger.result
      mysql-test/r/warnings.result
      mysql-test/t/trigger.test
      sql/field.cc
      sql/field.h
      sql/field_conv.cc
      sql/filesort.cc
      sql/ha_ndbcluster_cond.cc
      sql/item.cc
      sql/item.h
      sql/item_cmpfunc.cc
      sql/item_func.h
      sql/item_sum.cc
      sql/key.cc
      sql/log_event.cc
      sql/log_event_old.cc
      sql/opt_range.cc
      sql/opt_sum.cc
      sql/partition_info.cc
      sql/rpl_record.cc
      sql/sp_head.cc
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_handler.cc
      sql/sql_insert.cc
      sql/sql_load.cc
      sql/sql_partition.cc
      sql/sql_select.cc
      sql/sql_select.h
      sql/sql_show.cc
      sql/sql_table.cc
      sql/sql_trigger.cc
      sql/sql_union.cc
      sql/sql_update.cc
      sql/sql_view.cc
      sql/table.cc
      sql/table.h
      sql/unireg.cc
      storage/csv/ha_tina.cc
      storage/federated/ha_federated.cc
      storage/heap/ha_heap.cc
      storage/ibmdb2i/ha_ibmdb2i.cc
      storage/innobase/handler/ha_innodb.cc
      storage/myisam/ha_myisam.cc
=== modified file 'include/mysql_com.h'
--- a/include/mysql_com.h	2010-05-28 05:49:57 +0000
+++ b/include/mysql_com.h	2010-06-01 13:33:14 +0000
@@ -97,6 +97,7 @@ enum enum_server_command
 #define UNSIGNED_FLAG	32		/* Field is unsigned */
 #define ZEROFILL_FLAG	64		/* Field is zerofill */
 #define BINARY_FLAG	128		/* Field is binary   */
+#define TEMPORARY_NULLABLE_FLAG (1<< 22) /* Field is temporary nullable for trigger processing */
 
 /* The following are only sent to new clients */
 #define ENUM_FLAG	256		/* field is an enum */

=== modified file 'mysql-test/r/trigger.result'
--- a/mysql-test/r/trigger.result	2010-05-20 12:39:00 +0000
+++ b/mysql-test/r/trigger.result	2010-06-01 13:33:14 +0000
@@ -212,12 +212,14 @@ end if;
 end|
 insert into t3 values (1);
 insert into t1 values (4, "four", 1), (5, "five", 2);
-ERROR 23000: Column 'id' cannot be null
+Warnings:
+Warning	1048	Column 'id' cannot be null
 select * from t1;
 id	data	fk
 1	one	NULL
 2	two	NULL
 4	four	1
+0	five	2
 select * from t2;
 event
 INSERT INTO t1 id=1 data='one'
@@ -2284,4 +2286,135 @@ INSERT INTO t1 VALUES (1, 'example.com')
 INSERT INTO t2 VALUES ('Yes', 1, NULL, 'spamfilter','scan_incoming');
 DROP TRIGGER t2_ai;
 DROP TABLE t1, t2, t3;
+#
+# Bug#6295 Triggers are not processed for NOT NULL columns
+#
+DROP TABLE IF EXISTS t1;
+DROP TRIGGER IF EXISTS t1_bi;
+DROP TRIGGER IF EXISTS t1_bu;
+# Test 1: BEFORE INSERT, NOT NULL
+CREATE TABLE t1(a INT NOT NULL);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1;
+INSERT INTO t1 VALUES(NULL);
+SELECT * FROM t1;
+a
+1
+DROP TRIGGER t1_bi;
+DELETE FROM t1;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = NULL;
+INSERT INTO t1 VALUES(1);
+ERROR 23000: Column 'a' cannot be null
+SELECT * FROM t1;
+a
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+# Test 2: BEFORE UPDATE, NOT NULL
+CREATE TABLE t1(a INT NOT NULL);
+CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET new.a = 2;
+INSERT INTO t1 VALUES(1);
+UPDATE t1 SET a = NULL WHERE a = 1;
+SELECT * FROM t1;
+a
+2
+DROP TRIGGER t1_bu;
+DELETE FROM t1;
+CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET new.a = NULL;
+INSERT INTO t1 VALUES(1);
+UPDATE t1 SET a = 2 WHERE a = 1;
+Warnings:
+Warning	1048	Column 'a' cannot be null
+SELECT * FROM t1;
+a
+0
+DROP TRIGGER t1_bu;
+DROP TABLE t1;
+# Test 3: Using illegal NULL-value as r-value
+CREATE TABLE t1(a INT NOT NULL, b INT);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.b = new.a;
+SET new.a = 1;
+END|
+INSERT INTO t1(a) VALUES(NULL);
+SELECT * FROM t1;
+a	b
+1	NULL
+DROP TRIGGER t1_bi;
+DELETE FROM t1;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.a = 1;
+SET new.b = new.a;
+END|
+INSERT INTO t1(a) VALUES(NULL);
+SELECT * FROM t1;
+a	b
+1	1
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+# Test 4: Temporarily setting to illegal NULL-value in trigger
+CREATE TABLE t1(a INT NOT NULL);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.a = NULL;
+SET new.a = 2;
+END|
+INSERT INTO t1 VALUES(1);
+SELECT * FROM t1;
+a
+2
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+# Test 5: Using IS NULL inside trigger
+CREATE TABLE t1(a INT NOT NULL);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET @a:= new.a IS NULL;
+SET new.a = 1;
+END|
+INSERT INTO t1 VALUES(NULL);
+SELECT @a;
+@a
+1
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+CREATE TABLE t1(a INT NOT NULL, b INT);
+INSERT INTO t1 VALUES(1, NULL);
+CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET @a = new.a IS NULL;
+SET @b = old.a IS NULL;
+SET @c = new.b IS NULL;
+SET @d = old.b IS NULL;
+SET new.a = 2;
+END|
+UPDATE t1 SET a = NULL;
+SELECT @a, @b, @c, @d;
+@a	@b	@c	@d
+1	0	1	1
+DROP TRIGGER t1_bu;
+DROP TABLE t1;
+# Test 6: Nullability of non-updated columns
+CREATE TABLE t1(a INT, b INT NOT NULL);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.b = NULL;
+INSERT INTO t1(a) VALUES(NULL);
+ERROR 23000: Column 'b' cannot be null
+SELECT * FROM t1;
+a	b
+DROP TRIGGER t1_bi;
+DELETE FROM t1;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.b = new.a;
+IF new.b IS NULL THEN SET new.b = 1;
+END IF;
+END|
+INSERT INTO t1(a) VALUES(NULL);
+Warnings:
+Warning	1364	Field 'b' doesn't have a default value
+SELECT * FROM t1;
+a	b
+NULL	1
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
 End of 6.0 tests.

=== modified file 'mysql-test/r/warnings.result'
--- a/mysql-test/r/warnings.result	2010-03-20 09:35:40 +0000
+++ b/mysql-test/r/warnings.result	2010-06-01 13:33:14 +0000
@@ -115,8 +115,8 @@ Warnings:
 Warning	1265	Data truncated for column 'b' at row 1
 Warning	1265	Data truncated for column 'b' at row 2
 Warning	1265	Data truncated for column 'b' at row 3
-Warning	1048	Column 'a' cannot be null
 Warning	1265	Data truncated for column 'b' at row 4
+Warning	1048	Column 'a' cannot be null
 insert into t2(b) values('mysqlab');
 Warnings:
 Warning	1364	Field 'a' doesn't have a default value

=== modified file 'mysql-test/t/trigger.test'
--- a/mysql-test/t/trigger.test	2010-05-20 12:39:00 +0000
+++ b/mysql-test/t/trigger.test	2010-06-01 13:33:14 +0000
@@ -241,7 +241,6 @@ begin
 end|
 delimiter ;|
 insert into t3 values (1);
---error ER_BAD_NULL_ERROR
 insert into t1 values (4, "four", 1), (5, "five", 2);
 select * from t1;
 select * from t2;
@@ -2635,4 +2634,152 @@ INSERT INTO t2 VALUES ('Yes', 1, NULL, '
 DROP TRIGGER t2_ai;
 DROP TABLE t1, t2, t3;
 
+
+--echo #
+--echo # Bug#6295 Triggers are not processed for NOT NULL columns
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TRIGGER IF EXISTS t1_bi;
+DROP TRIGGER IF EXISTS t1_bu;
+--enable_warnings
+
+--echo # Test 1: BEFORE INSERT, NOT NULL
+
+CREATE TABLE t1(a INT NOT NULL);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1;
+# This should work
+INSERT INTO t1 VALUES(NULL);
+SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DELETE FROM t1;
+
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = NULL;
+# This should not work
+# For a single-row INSERT, no warning occurs when NULL is inserted into a NOT NULL column.
+# Instead, the statement fails with an error.
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1 VALUES(1);
+SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+
+--echo # Test 2: BEFORE UPDATE, NOT NULL
+
+CREATE TABLE t1(a INT NOT NULL);
+CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET new.a = 2;
+INSERT INTO t1 VALUES(1);
+# This should work
+UPDATE t1 SET a = NULL WHERE a = 1;
+SELECT * FROM t1;
+DROP TRIGGER t1_bu;
+DELETE FROM t1;
+
+CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET new.a = NULL;
+INSERT INTO t1 VALUES(1);
+# This should give a warning
+UPDATE t1 SET a = 2 WHERE a = 1;
+SELECT * FROM t1;
+DROP TRIGGER t1_bu;
+DROP TABLE t1;
+
+--echo # Test 3: Using illegal NULL-value as r-value
+
+CREATE TABLE t1(a INT NOT NULL, b INT);
+delimiter |;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+  SET new.b = new.a;
+  SET new.a = 1;
+END|
+delimiter ;|
+INSERT INTO t1(a) VALUES(NULL);
+SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DELETE FROM t1;
+
+delimiter |;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+  SET new.a = 1;
+  SET new.b = new.a;
+END|
+delimiter ;|
+INSERT INTO t1(a) VALUES(NULL);
+SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+
+--echo # Test 4: Temporarily setting to illegal NULL-value in trigger
+
+CREATE TABLE t1(a INT NOT NULL);
+delimiter |;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+  SET new.a = NULL;
+  SET new.a = 2;
+END|
+delimiter ;|
+INSERT INTO t1 VALUES(1);
+SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+
+--echo # Test 5: Using IS NULL inside trigger
+
+CREATE TABLE t1(a INT NOT NULL);
+delimiter |;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+  SET @a:= new.a IS NULL;
+  SET new.a = 1;
+END|
+delimiter ;|
+INSERT INTO t1 VALUES(NULL);
+SELECT @a;
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+
+CREATE TABLE t1(a INT NOT NULL, b INT);
+INSERT INTO t1 VALUES(1, NULL);
+delimiter |;
+CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+  SET @a = new.a IS NULL;
+  SET @b = old.a IS NULL;
+  SET @c = new.b IS NULL;
+  SET @d = old.b IS NULL;
+  SET new.a = 2;
+END|
+delimiter ;|
+UPDATE t1 SET a = NULL;
+SELECT @a, @b, @c, @d;
+DROP TRIGGER t1_bu;
+DROP TABLE t1;
+
+--echo # Test 6: Nullability of non-updated columns
+
+CREATE TABLE t1(a INT, b INT NOT NULL);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.b = NULL;
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1(a) VALUES(NULL);
+SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DELETE FROM t1;
+
+delimiter |;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+  SET new.b = new.a;
+  IF new.b IS NULL THEN SET new.b = 1;
+  END IF;
+END|
+delimiter ;|
+INSERT INTO t1(a) VALUES(NULL);
+SELECT * FROM t1;
+DROP TRIGGER t1_bi;
+DROP TABLE t1;
+
+
 --echo End of 6.0 tests.

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2010-05-31 12:38:54 +0000
+++ b/sql/field.cc	2010-06-01 13:33:14 +0000
@@ -1107,10 +1107,10 @@ bool Field::type_can_have_key_part(enum 
   Numeric fields base class constructor.
 */
 Field_num::Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
-                     uchar null_bit_arg, utype unireg_check_arg,
-                     const char *field_name_arg,
+                     uchar null_bit_arg, bool is_nullable,
+                     utype unireg_check_arg, const char *field_name_arg,
                      uint8 dec_arg, bool zero_arg, bool unsigned_arg)
-  :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+  :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
          unireg_check_arg, field_name_arg),
   dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
 {
@@ -1355,8 +1355,8 @@ String *Field::val_int_as_str(String *va
 
 /// This is used as a table name when the table structure is not set up
 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)
+             uchar null_bit_arg, bool is_nullable,
+             utype unireg_check_arg, const char *field_name_arg)
   :ptr(ptr_arg), null_ptr(null_ptr_arg),
    table(0), orig_table(0), table_name(0),
    field_name(field_name_arg),
@@ -1365,13 +1365,56 @@ Field::Field(uchar *ptr_arg,uint32 lengt
    field_length(length_arg), null_bit(null_bit_arg), 
    is_created_from_null_item(FALSE)
 {
-  flags=null_ptr ? 0: NOT_NULL_FLAG;
+  flags=is_nullable ? 0: NOT_NULL_FLAG;
   comment.str= (char*) "";
   comment.length=0;
   field_index= 0;
 }
 
 
+/**
+   Check that the current value stored in the Field does not break
+   any constraints defined for the Field.
+
+   Currently it only checks NOT NULL constraints.
+
+   @retval
+     0   Constraints not broken, or warning reported.
+   @retval
+     -1  Constraints broken, error reported.
+*/
+int Field::check_constraints()
+{
+  set_temporary_nullable(FALSE);
+  // Check for NULL in NOT NULL fields
+  if (!real_is_nullable() && null_ptr && (null_ptr[0] & null_bit))
+  {
+    if (this == table->next_number_field ||
+        (table->s->found_next_number_field &&
+         this == table->field[table->s->found_next_number_field -
+                              table->s->field]))
+      return 0;
+    if (type() == MYSQL_TYPE_TIMESTAMP)
+      return 0;
+    set_notnull();
+    switch (table->in_use->count_cuted_fields) {
+    case CHECK_FIELD_WARN:
+      set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1);
+      /* fall through */
+    case CHECK_FIELD_IGNORE:
+      return 0;
+    case CHECK_FIELD_ERROR_FOR_NULL:
+      if (!table->in_use->no_errors)
+        my_error(ER_BAD_NULL_ERROR, MYF(0), field_name);
+      return -1;
+    }
+    DBUG_ASSERT(0); // impossible
+    return -1;
+  }
+  return 0;
+}
+
+
 void Field::hash(ulong *nr, ulong *nr2)
 {
   if (is_null())
@@ -1725,9 +1768,10 @@ my_decimal* Field_num::val_decimal(my_de
 
 
 Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
-                     uchar null_bit_arg, utype unireg_check_arg,
+                     uchar null_bit_arg, bool is_nullable,
+                     utype unireg_check_arg,
                      const char *field_name_arg, CHARSET_INFO *charset_arg)
-  :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+  :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
          unireg_check_arg, field_name_arg)
 {
   field_charset= charset_arg;
@@ -1879,7 +1923,7 @@ Field *Field::new_field(MEM_ROOT *root, 
 
 Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
                             uchar *new_ptr, uchar *new_null_ptr,
-                            uint new_null_bit)
+                            uint new_null_bit, bool is_nullable)
 {
   Field *tmp;
   if ((tmp= new_field(root, new_table, table == new_table)))
@@ -1887,6 +1931,7 @@ Field *Field::new_key_field(MEM_ROOT *ro
     tmp->ptr=      new_ptr;
     tmp->null_ptr= new_null_ptr;
     tmp->null_bit= new_null_bit;
+    tmp->flags=    is_nullable ? 0: NOT_NULL_FLAG;
   }
   return tmp;
 }
@@ -2531,12 +2576,12 @@ void Field_decimal::sql_type(String &res
 
 Field_new_decimal::Field_new_decimal(uchar *ptr_arg,
                                      uint32 len_arg, uchar *null_ptr_arg,
-                                     uchar null_bit_arg,
+                                     uchar null_bit_arg, bool is_nullable,
                                      enum utype unireg_check_arg,
                                      const char *field_name_arg,
                                      uint8 dec_arg,bool zero_arg,
                                      bool unsigned_arg)
-  :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+  :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
              unireg_check_arg, field_name_arg, dec_arg, zero_arg, unsigned_arg)
 {
   precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
@@ -2548,12 +2593,11 @@ Field_new_decimal::Field_new_decimal(uch
 
 
 Field_new_decimal::Field_new_decimal(uint32 len_arg,
-                                     bool maybe_null_arg,
+                                     bool is_nullable,
                                      const char *name,
                                      uint8 dec_arg,
                                      bool unsigned_arg)
-  :Field_num((uchar*) 0, len_arg,
-             maybe_null_arg ? (uchar*) "": 0, 0,
+  :Field_num((uchar*) 0, len_arg, is_nullable ? (uchar*) "": 0, 0, is_nullable,
              NONE, name, dec_arg, 0, unsigned_arg)
 {
   precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
@@ -4708,12 +4752,13 @@ void Field_double::sql_type(String &res)
 
 Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
                                  uchar *null_ptr_arg, uchar null_bit_arg,
+                                 bool is_nullable,
 				 enum utype unireg_check_arg,
 				 const char *field_name_arg,
 				 TABLE_SHARE *share,
 				 CHARSET_INFO *cs)
   :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
-	     unireg_check_arg, field_name_arg, cs)
+             is_nullable, unireg_check_arg, field_name_arg, cs)
 {
   /* For 4.0 MYD and 4.0 InnoDB compatibility */
   flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | BINARY_FLAG;
@@ -4728,12 +4773,12 @@ Field_timestamp::Field_timestamp(uchar *
 }
 
 
-Field_timestamp::Field_timestamp(bool maybe_null_arg,
+Field_timestamp::Field_timestamp(bool is_nullable,
                                  const char *field_name_arg,
                                  CHARSET_INFO *cs)
   :Field_str((uchar*) 0, MAX_DATETIME_WIDTH,
-             maybe_null_arg ? (uchar*) "": 0, 0,
-	     NONE, field_name_arg, cs)
+             is_nullable ? (uchar*) "": 0, 0,
+             is_nullable, NONE, field_name_arg, cs)
 {
   /* For 4.0 MYD and 4.0 InnoDB compatibility */
   flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | BINARY_FLAG;
@@ -6781,7 +6826,7 @@ Field *Field_string::new_field(MEM_ROOT 
   Field *field;
   if (type() != MYSQL_TYPE_VAR_STRING || keep_type)
     field= Field::new_field(root, new_table, keep_type);
-  else if ((field= new Field_varstring(field_length, maybe_null(), field_name,
+  else if ((field= new Field_varstring(field_length, is_nullable(), field_name,
                                        new_table->s, charset())))
   {
     /*
@@ -7229,14 +7274,15 @@ Field *Field_varstring::new_field(MEM_RO
 Field *Field_varstring::new_key_field(MEM_ROOT *root,
                                       TABLE *new_table,
                                       uchar *new_ptr, uchar *new_null_ptr,
-                                      uint new_null_bit)
+                                      uint new_null_bit, bool is_nullable)
 {
   Field_varstring *res;
   if ((res= (Field_varstring*) Field::new_key_field(root,
                                                     new_table,
                                                     new_ptr,
                                                     new_null_ptr,
-                                                    new_null_bit)))
+                                                    new_null_bit,
+                                                    is_nullable)))
   {
     /* Keys length prefixes are always packed with 2 bytes */
     res->length_bytes= 2;
@@ -7283,12 +7329,12 @@ void Field_varstring::hash(ulong *nr, ul
 ****************************************************************************/
 
 Field_blob::Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
-		       enum utype unireg_check_arg, const char *field_name_arg,
-                       TABLE_SHARE *share, uint blob_pack_length,
-		       CHARSET_INFO *cs)
+                       bool is_nullable, enum utype unireg_check_arg,
+                       const char *field_name_arg, TABLE_SHARE *share,
+                       uint blob_pack_length, CHARSET_INFO *cs)
   :Field_longstr(ptr_arg, BLOB_PACK_LENGTH_TO_MAX_LENGH(blob_pack_length),
-                 null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
-                 cs),
+                 null_ptr_arg, null_bit_arg, is_nullable, unireg_check_arg,
+                 field_name_arg, cs),
    packlength(blob_pack_length)
 {
   DBUG_ASSERT(blob_pack_length <= 4); // Only pack lengths 1-4 supported currently
@@ -8511,9 +8557,10 @@ uint Field_num::is_equal(Create_field *n
 */
 
 Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-                     uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
-                     enum utype unireg_check_arg, const char *field_name_arg)
-  : Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+                     uchar null_bit_arg, bool is_nullable, uchar *bit_ptr_arg,
+                     uchar bit_ofs_arg, enum utype unireg_check_arg,
+                     const char *field_name_arg)
+  : Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
           unireg_check_arg, field_name_arg),
     bit_ptr(bit_ptr_arg), bit_ofs(bit_ofs_arg), bit_len(len_arg & 7),
     bytes_in_rec(len_arg / 8)
@@ -8579,12 +8626,12 @@ Field_bit::do_last_null_byte() const
 Field *Field_bit::new_key_field(MEM_ROOT *root,
                                 TABLE *new_table,
                                 uchar *new_ptr, uchar *new_null_ptr,
-                                uint new_null_bit)
+                                uint new_null_bit, bool is_nullable)
 {
   Field_bit *res;
   if ((res= (Field_bit*) Field::new_key_field(root, new_table,
                                               new_ptr, new_null_ptr,
-                                              new_null_bit)))
+                                              new_null_bit, is_nullable)))
   {
     /* Move bits normally stored in null_pointer to new_ptr */
     res->bit_ptr= new_ptr;
@@ -9017,9 +9064,10 @@ void Field_bit::set_default()
 
 Field_bit_as_char::Field_bit_as_char(uchar *ptr_arg, uint32 len_arg,
                                      uchar *null_ptr_arg, uchar null_bit_arg,
+                                     bool is_nullable,
                                      enum utype unireg_check_arg,
                                      const char *field_name_arg)
-  :Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0, 0,
+  :Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable, 0, 0,
              unireg_check_arg, field_name_arg)
 {
   flags|= UNSIGNED_FLAG;
@@ -9696,26 +9744,19 @@ Field *make_field(TABLE_SHARE *share, uc
 {
   uchar *UNINIT_VAR(bit_ptr);
   uchar UNINIT_VAR(bit_offset);
+  bool is_nullable= f_maybe_null(pack_flag);
   if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
   {
     bit_ptr= null_pos;
     bit_offset= null_bit;
-    if (f_maybe_null(pack_flag))         // if null field
+    if (is_nullable)         // if null field
     {
        bit_ptr+= (null_bit == 7);        // shift bit_ptr and bit_offset
        bit_offset= (bit_offset + 1) & 7;
     }
   }
 
-  if (!f_maybe_null(pack_flag))
-  {
-    null_pos=0;
-    null_bit=0;
-  }
-  else
-  {
-    null_bit= ((uchar) 1) << null_bit;
-  }
+  null_bit= ((uchar) 1) << null_bit;
 
   switch (field_type) {
   case MYSQL_TYPE_DATE:
@@ -9742,13 +9783,13 @@ Field *make_field(TABLE_SHARE *share, uc
       if (field_type == MYSQL_TYPE_STRING ||
           field_type == MYSQL_TYPE_DECIMAL ||   // 3.23 or 4.0 string
           field_type == MYSQL_TYPE_VAR_STRING)
-        return new Field_string(ptr,field_length,null_pos,null_bit,
+        return new Field_string(ptr,field_length,null_pos,null_bit,is_nullable,
                                 unireg_check, field_name,
                                 field_charset);
       if (field_type == MYSQL_TYPE_VARCHAR)
         return new Field_varstring(ptr,field_length,
                                    HA_VARCHAR_PACKLENGTH(field_length),
-                                   null_pos,null_bit,
+                                   null_pos,null_bit, is_nullable,
                                    unireg_check, field_name,
                                    share,
                                    field_charset);
@@ -9761,22 +9802,22 @@ Field *make_field(TABLE_SHARE *share, uc
 
 #ifdef HAVE_SPATIAL
     if (f_is_geom(pack_flag))
-      return new Field_geom(ptr,null_pos,null_bit,
+      return new Field_geom(ptr,null_pos,null_bit,is_nullable,
 			    unireg_check, field_name, share,
 			    pack_length, geom_type);
 #endif
     if (f_is_blob(pack_flag))
-      return new Field_blob(ptr,null_pos,null_bit,
+      return new Field_blob(ptr,null_pos,null_bit,is_nullable,
 			    unireg_check, field_name, share,
 			    pack_length, field_charset);
     if (interval)
     {
       if (f_is_enum(pack_flag))
-	return new Field_enum(ptr,field_length,null_pos,null_bit,
+        return new Field_enum(ptr,field_length,null_pos,null_bit,is_nullable,
 				  unireg_check, field_name,
 				  pack_length, interval, field_charset);
       else
-	return new Field_set(ptr,field_length,null_pos,null_bit,
+        return new Field_set(ptr,field_length,null_pos,null_bit,is_nullable,
 			     unireg_check, field_name,
 			     pack_length, interval, field_charset);
     }
@@ -9784,82 +9825,82 @@ Field *make_field(TABLE_SHARE *share, uc
 
   switch (field_type) {
   case MYSQL_TYPE_DECIMAL:
-    return new Field_decimal(ptr,field_length,null_pos,null_bit,
+    return new Field_decimal(ptr,field_length,null_pos,null_bit,is_nullable,
 			     unireg_check, field_name,
 			     f_decimals(pack_flag),
 			     f_is_zerofill(pack_flag) != 0,
 			     f_is_dec(pack_flag) == 0);
   case MYSQL_TYPE_NEWDECIMAL:
-    return new Field_new_decimal(ptr,field_length,null_pos,null_bit,
+    return new Field_new_decimal(ptr,field_length,null_pos,null_bit,is_nullable,
                                  unireg_check, field_name,
                                  f_decimals(pack_flag),
                                  f_is_zerofill(pack_flag) != 0,
                                  f_is_dec(pack_flag) == 0);
   case MYSQL_TYPE_FLOAT:
-    return new Field_float(ptr,field_length,null_pos,null_bit,
+    return new Field_float(ptr,field_length,null_pos,null_bit,is_nullable,
 			   unireg_check, field_name,
 			   f_decimals(pack_flag),
 			   f_is_zerofill(pack_flag) != 0,
 			   f_is_dec(pack_flag)== 0);
   case MYSQL_TYPE_DOUBLE:
-    return new Field_double(ptr,field_length,null_pos,null_bit,
+    return new Field_double(ptr,field_length,null_pos,null_bit,is_nullable,
 			    unireg_check, field_name,
 			    f_decimals(pack_flag),
 			    f_is_zerofill(pack_flag) != 0,
 			    f_is_dec(pack_flag)== 0);
   case MYSQL_TYPE_TINY:
-    return new Field_tiny(ptr,field_length,null_pos,null_bit,
+    return new Field_tiny(ptr,field_length,null_pos,null_bit,is_nullable,
 			  unireg_check, field_name,
 			  f_is_zerofill(pack_flag) != 0,
 			  f_is_dec(pack_flag) == 0);
   case MYSQL_TYPE_SHORT:
-    return new Field_short(ptr,field_length,null_pos,null_bit,
+    return new Field_short(ptr,field_length,null_pos,null_bit,is_nullable,
 			   unireg_check, field_name,
 			   f_is_zerofill(pack_flag) != 0,
 			   f_is_dec(pack_flag) == 0);
   case MYSQL_TYPE_INT24:
-    return new Field_medium(ptr,field_length,null_pos,null_bit,
+    return new Field_medium(ptr,field_length,null_pos,null_bit,is_nullable,
 			    unireg_check, field_name,
 			    f_is_zerofill(pack_flag) != 0,
 			    f_is_dec(pack_flag) == 0);
   case MYSQL_TYPE_LONG:
-    return new Field_long(ptr,field_length,null_pos,null_bit,
+    return new Field_long(ptr,field_length,null_pos,null_bit,is_nullable,
 			   unireg_check, field_name,
 			   f_is_zerofill(pack_flag) != 0,
 			   f_is_dec(pack_flag) == 0);
   case MYSQL_TYPE_LONGLONG:
-    return new Field_longlong(ptr,field_length,null_pos,null_bit,
+    return new Field_longlong(ptr,field_length,null_pos,null_bit,is_nullable,
 			      unireg_check, field_name,
 			      f_is_zerofill(pack_flag) != 0,
 			      f_is_dec(pack_flag) == 0);
   case MYSQL_TYPE_TIMESTAMP:
-    return new Field_timestamp(ptr,field_length, null_pos, null_bit,
+    return new Field_timestamp(ptr,field_length, null_pos, null_bit,is_nullable,
                                unireg_check, field_name, share,
                                field_charset);
   case MYSQL_TYPE_YEAR:
-    return new Field_year(ptr,field_length,null_pos,null_bit,
+    return new Field_year(ptr,field_length,null_pos,null_bit,is_nullable,
 			  unireg_check, field_name);
   case MYSQL_TYPE_DATE:
-    return new Field_date(ptr,null_pos,null_bit,
+    return new Field_date(ptr,null_pos,null_bit,is_nullable,
 			  unireg_check, field_name, field_charset);
   case MYSQL_TYPE_NEWDATE:
-    return new Field_newdate(ptr,null_pos,null_bit,
+    return new Field_newdate(ptr,null_pos,null_bit,is_nullable,
 			     unireg_check, field_name, field_charset);
   case MYSQL_TYPE_TIME:
-    return new Field_time(ptr,null_pos,null_bit,
+    return new Field_time(ptr,null_pos,null_bit,is_nullable,
 			  unireg_check, field_name, field_charset);
   case MYSQL_TYPE_DATETIME:
-    return new Field_datetime(ptr,null_pos,null_bit,
+    return new Field_datetime(ptr,null_pos,null_bit,is_nullable,
 			      unireg_check, field_name, field_charset);
   case MYSQL_TYPE_NULL:
     return new Field_null(ptr, field_length, unireg_check, field_name,
                           field_charset);
   case MYSQL_TYPE_BIT:
     return f_bit_as_char(pack_flag) ?
-           new Field_bit_as_char(ptr, field_length, null_pos, null_bit,
-                                 unireg_check, field_name) :
-           new Field_bit(ptr, field_length, null_pos, null_bit, bit_ptr,
-                         bit_offset, unireg_check, field_name);
+      new Field_bit_as_char(ptr, field_length, null_pos, null_bit,
+                            is_nullable, unireg_check, field_name) :
+      new Field_bit(ptr, field_length, null_pos, null_bit, is_nullable, bit_ptr,
+                    bit_offset, unireg_check, field_name);
 
   default:					// Impossible (Wrong version)
     break;

=== modified file 'sql/field.h'
--- a/sql/field.h	2010-04-27 10:01:45 +0000
+++ b/sql/field.h	2010-06-01 13:33:14 +0000
@@ -143,7 +143,7 @@ public:
   bool is_created_from_null_item;
 
   Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
-        uchar null_bit_arg, utype unireg_check_arg,
+        uchar null_bit_arg, bool is_nullable, utype unireg_check_arg,
         const char *field_name_arg);
   virtual ~Field() {}
   /* Store functions returns 1 on overflow and -1 on fatal error */
@@ -237,7 +237,7 @@ public:
     my_ptrdiff_t l_offset= (my_ptrdiff_t) (table->s->default_values -
 					  table->record[0]);
     memcpy(ptr, ptr + l_offset, pack_length());
-    if (null_ptr)
+    if (real_is_nullable())
       *null_ptr= ((*null_ptr & (uchar) ~null_bit) |
 		  (null_ptr[l_offset] & null_bit));
   }
@@ -270,31 +270,33 @@ public:
   virtual void sql_type(String &str) const =0;
   virtual uint size_of() const =0;		// For new field
   inline bool is_null(my_ptrdiff_t row_offset= 0)
-  { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; }
+  { return real_is_nullable() ? (null_ptr[row_offset] & null_bit ? TRUE : FALSE) : table->null_row; }
   inline bool is_real_null(my_ptrdiff_t row_offset= 0)
-    { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : 0; }
+  { return real_is_nullable() ? (null_ptr[row_offset] & null_bit ? TRUE : FALSE) : FALSE; }
   inline bool is_null_in_record(const uchar *record)
   {
-    if (!null_ptr)
-      return 0;
-    return test(record[(uint) (null_ptr -table->record[0])] &
-		null_bit);
-  }
-  inline bool is_null_in_record_with_offset(my_ptrdiff_t offset)
-  {
-    if (!null_ptr)
-      return 0;
-    return test(null_ptr[offset] & null_bit);
+    if (!real_is_nullable())
+      return FALSE;
+    return test(record[(uint) (null_ptr -table->record[0])] & null_bit);
   }
   inline void set_null(my_ptrdiff_t row_offset= 0)
-    { if (null_ptr) null_ptr[row_offset]|= null_bit; }
+  { if (real_is_nullable()) null_ptr[row_offset]|= null_bit; }
   inline void set_notnull(my_ptrdiff_t row_offset= 0)
-    { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; }
-  inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; }
+  { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; }
+  inline bool is_nullable(void) { return real_is_nullable() || table->maybe_null; }
   /**
      Signals that this field is NULL-able.
   */
-  inline bool real_maybe_null(void) { return null_ptr != 0; }
+  inline bool real_is_nullable(void)
+  { return !(flags & NOT_NULL_FLAG) || (flags & TEMPORARY_NULLABLE_FLAG); }
+  inline void set_temporary_nullable(bool temporary_nullable)
+  {
+    if (!temporary_nullable)
+      flags &= ~TEMPORARY_NULLABLE_FLAG;
+    else if (null_ptr)
+      flags |= TEMPORARY_NULLABLE_FLAG;
+  }
+  int check_constraints();
 
   enum {
     LAST_NULL_BYTE_UNDEF= 0
@@ -338,7 +340,7 @@ public:
                            bool keep_type);
   virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
                                uchar *new_ptr, uchar *new_null_ptr,
-                               uint new_null_bit);
+                               uint new_null_bit, bool is_nullable);
   Field *clone(MEM_ROOT *mem_root, TABLE *new_table);
   inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
   {
@@ -638,8 +640,8 @@ public:
   const uint8 dec;
   bool zerofill,unsigned_flag;	// Purify cannot handle bit fields
   Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
-	    uchar null_bit_arg, utype unireg_check_arg,
-	    const char *field_name_arg,
+            uchar null_bit_arg, bool is_nullable, utype unireg_check_arg,
+            const char *field_name_arg,
             uint8 dec_arg, bool zero_arg, bool unsigned_arg);
   Item_result result_type () const { return REAL_RESULT; }
   enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
@@ -676,8 +678,8 @@ protected:
   enum Derivation field_derivation;
 public:
   Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
-	    uchar null_bit_arg, utype unireg_check_arg,
-	    const char *field_name_arg, CHARSET_INFO *charset);
+            uchar null_bit_arg, bool is_nullable, utype unireg_check_arg,
+            const char *field_name_arg, CHARSET_INFO *charset);
   Item_result result_type () const { return STRING_RESULT; }
   uint decimals() const { return NOT_FIXED_DEC; }
   int  store(double nr);
@@ -712,10 +714,10 @@ protected:
                                bool count_spaces);
 public:
   Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-                uchar null_bit_arg, utype unireg_check_arg,
+                uchar null_bit_arg, bool is_nullable, utype unireg_check_arg,
                 const char *field_name_arg, CHARSET_INFO *charset_arg)
-    :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
-               field_name_arg, charset_arg)
+    :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg, charset_arg)
     {}
 
   int store_decimal(const my_decimal *d);
@@ -728,11 +730,12 @@ public:
   my_bool not_fixed;
 
   Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-             uchar null_bit_arg, utype unireg_check_arg,
+             uchar null_bit_arg, bool is_nullable, utype unireg_check_arg,
              const char *field_name_arg,
              uint8 dec_arg, bool zero_arg, bool unsigned_arg)
-    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
-               field_name_arg, dec_arg, zero_arg, unsigned_arg),
+    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg, dec_arg, zero_arg,
+               unsigned_arg),
     not_fixed(dec_arg >= NOT_FIXED_DEC)
     {}
   int store_decimal(const my_decimal *);
@@ -750,10 +753,10 @@ public:
 class Field_decimal :public Field_real {
 public:
   Field_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-		uchar null_bit_arg,
-		enum utype unireg_check_arg, const char *field_name_arg,
-		uint8 dec_arg,bool zero_arg,bool unsigned_arg)
-    :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+                uchar null_bit_arg, bool is_nullable,
+                enum utype unireg_check_arg, const char *field_name_arg,
+                uint8 dec_arg,bool zero_arg,bool unsigned_arg)
+    :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
                 unireg_check_arg, field_name_arg,
                 dec_arg, zero_arg, unsigned_arg)
     {}
@@ -800,10 +803,10 @@ public:
     CREATE TABLE ( DECIMAL(x,y)) 
   */
   Field_new_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-                    uchar null_bit_arg,
+                    uchar null_bit_arg, bool is_nullable,
                     enum utype unireg_check_arg, const char *field_name_arg,
                     uint8 dec_arg, bool zero_arg, bool unsigned_arg);
-  Field_new_decimal(uint32 len_arg, bool maybe_null_arg,
+  Field_new_decimal(uint32 len_arg, bool is_nullable,
                     const char *field_name_arg, uint8 dec_arg,
                     bool unsigned_arg);
   enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;}
@@ -842,12 +845,12 @@ public:
 class Field_tiny :public Field_num {
 public:
   Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	     uchar null_bit_arg,
-	     enum utype unireg_check_arg, const char *field_name_arg,
-	     bool zero_arg, bool unsigned_arg)
-    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg,
-	       0, zero_arg,unsigned_arg)
+             uchar null_bit_arg, bool is_nullable,
+             enum utype unireg_check_arg, const char *field_name_arg,
+             bool zero_arg, bool unsigned_arg)
+    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg,
+               0, zero_arg,unsigned_arg)
     {}
   enum Item_result result_type () const { return INT_RESULT; }
   enum_field_types type() const { return MYSQL_TYPE_TINY;}
@@ -886,17 +889,12 @@ public:
 class Field_short :public Field_num {
 public:
   Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	      uchar null_bit_arg,
-	      enum utype unireg_check_arg, const char *field_name_arg,
-	      bool zero_arg, bool unsigned_arg)
-    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg,
-	       0, zero_arg,unsigned_arg)
-    {}
-  Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
-	      bool unsigned_arg)
-    :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
-	       NONE, field_name_arg, 0, 0, unsigned_arg)
+              uchar null_bit_arg, bool is_nullable,
+              enum utype unireg_check_arg, const char *field_name_arg,
+              bool zero_arg, bool unsigned_arg)
+    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg,
+               0, zero_arg,unsigned_arg)
     {}
   enum Item_result result_type () const { return INT_RESULT; }
   enum_field_types type() const { return MYSQL_TYPE_SHORT;}
@@ -960,12 +958,12 @@ public:
 class Field_medium :public Field_num {
 public:
   Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	      uchar null_bit_arg,
-	      enum utype unireg_check_arg, const char *field_name_arg,
-	      bool zero_arg, bool unsigned_arg)
-    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg,
-	       0, zero_arg,unsigned_arg)
+               uchar null_bit_arg, bool is_nullable,
+               enum utype unireg_check_arg, const char *field_name_arg,
+               bool zero_arg, bool unsigned_arg)
+    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg,
+               0, zero_arg,unsigned_arg)
     {}
   enum Item_result result_type () const { return INT_RESULT; }
   enum_field_types type() const { return MYSQL_TYPE_INT24;}
@@ -1002,18 +1000,18 @@ public:
 class Field_long :public Field_num {
 public:
   Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	     uchar null_bit_arg,
-	     enum utype unireg_check_arg, const char *field_name_arg,
-	     bool zero_arg, bool unsigned_arg)
-    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg,
-	       0, zero_arg,unsigned_arg)
-    {}
-  Field_long(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
-	     bool unsigned_arg)
-    :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
-	       NONE, field_name_arg,0,0,unsigned_arg)
+             uchar null_bit_arg, bool is_nullable,
+             enum utype unireg_check_arg, const char *field_name_arg,
+             bool zero_arg, bool unsigned_arg)
+    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg,
+               0, zero_arg,unsigned_arg)
     {}
+  Field_long(uint32 len_arg,bool is_nullable, const char *field_name_arg,
+             bool unsigned_arg)
+    :Field_num((uchar*) 0, len_arg, is_nullable ? (uchar*) "": 0,0,
+               is_nullable, NONE, field_name_arg,0,0,unsigned_arg)
+               {}
   enum Item_result result_type () const { return INT_RESULT; }
   enum_field_types type() const { return MYSQL_TYPE_LONG;}
   enum ha_base_keytype key_type() const
@@ -1050,19 +1048,19 @@ public:
 class Field_longlong :public Field_num {
 public:
   Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	      uchar null_bit_arg,
-	      enum utype unireg_check_arg, const char *field_name_arg,
-	      bool zero_arg, bool unsigned_arg)
-    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg,
-	       0, zero_arg,unsigned_arg)
-    {}
-  Field_longlong(uint32 len_arg,bool maybe_null_arg,
-		 const char *field_name_arg,
-		  bool unsigned_arg)
-    :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
-	       NONE, field_name_arg,0,0,unsigned_arg)
+                 uchar null_bit_arg, bool is_nullable,
+                 enum utype unireg_check_arg, const char *field_name_arg,
+                 bool zero_arg, bool unsigned_arg)
+    :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg,
+               0, zero_arg,unsigned_arg)
     {}
+  Field_longlong(uint32 len_arg,bool is_nullable,
+                 const char *field_name_arg,
+                 bool unsigned_arg)
+    :Field_num((uchar*) 0, len_arg, is_nullable ? (uchar*) "": 0,0,
+                is_nullable, NONE, field_name_arg,0,0,unsigned_arg)
+               {}
   enum Item_result result_type () const { return INT_RESULT; }
   enum_field_types type() const { return MYSQL_TYPE_LONGLONG;}
   enum ha_base_keytype key_type() const
@@ -1104,18 +1102,13 @@ public:
 class Field_float :public Field_real {
 public:
   Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	      uchar null_bit_arg,
-	      enum utype unireg_check_arg, const char *field_name_arg,
+              uchar null_bit_arg, bool is_nullable,
+              enum utype unireg_check_arg, const char *field_name_arg,
               uint8 dec_arg,bool zero_arg,bool unsigned_arg)
-    :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+    :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
                 unireg_check_arg, field_name_arg,
                 dec_arg, zero_arg, unsigned_arg)
-    {}
-  Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
-	      uint8 dec_arg)
-    :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
-                NONE, field_name_arg, dec_arg, 0, 0)
-    {}
+  {}
   enum_field_types type() const { return MYSQL_TYPE_FLOAT;}
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
   int store(const char *to,uint length,CHARSET_INFO *charset);
@@ -1139,23 +1132,23 @@ private:
 class Field_double :public Field_real {
 public:
   Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	       uchar null_bit_arg,
-	       enum utype unireg_check_arg, const char *field_name_arg,
-	       uint8 dec_arg,bool zero_arg,bool unsigned_arg)
-    :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+               uchar null_bit_arg, bool is_nullable,
+               enum utype unireg_check_arg, const char *field_name_arg,
+               uint8 dec_arg,bool zero_arg,bool unsigned_arg)
+    :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
                 unireg_check_arg, field_name_arg,
                 dec_arg, zero_arg, unsigned_arg)
     {}
-  Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
-	       uint8 dec_arg)
-    :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
-                NONE, field_name_arg, dec_arg, 0, 0)
-    {}
-  Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
+  Field_double(uint32 len_arg, bool is_nullable, const char *field_name_arg,
+               uint8 dec_arg)
+    :Field_real((uchar*) 0, len_arg, is_nullable ? (uchar*) "" : 0, (uint) 0,
+                is_nullable, NONE, field_name_arg, dec_arg, 0, 0)
+                {}
+  Field_double(uint32 len_arg, bool is_nullable, const char *field_name_arg,
 	       uint8 dec_arg, my_bool not_fixed_arg)
-    :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
-                NONE, field_name_arg, dec_arg, 0, 0)
-    {not_fixed= not_fixed_arg; }
+    :Field_real((uchar*) 0, len_arg, is_nullable ? (uchar*) "" : 0, (uint) 0,
+                is_nullable, NONE, field_name_arg, dec_arg, 0, 0)
+                {not_fixed= not_fixed_arg; }
   enum_field_types type() const { return MYSQL_TYPE_DOUBLE;}
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
   int  store(const char *to,uint length,CHARSET_INFO *charset);
@@ -1184,7 +1177,7 @@ public:
   Field_null(uchar *ptr_arg, uint32 len_arg,
 	     enum utype unireg_check_arg, const char *field_name_arg,
 	     CHARSET_INFO *cs)
-    :Field_str(ptr_arg, len_arg, null, 1,
+    :Field_str(ptr_arg, len_arg, null, 1, TRUE,
 	       unireg_check_arg, field_name_arg, cs)
     {}
   enum_field_types type() const { return MYSQL_TYPE_NULL;}
@@ -1211,11 +1204,11 @@ public:
 class Field_timestamp :public Field_str {
 public:
   Field_timestamp(uchar *ptr_arg, uint32 len_arg,
-                  uchar *null_ptr_arg, uchar null_bit_arg,
-		  enum utype unireg_check_arg, const char *field_name_arg,
-		  TABLE_SHARE *share, CHARSET_INFO *cs);
-  Field_timestamp(bool maybe_null_arg, const char *field_name_arg,
-		  CHARSET_INFO *cs);
+                  uchar *null_ptr_arg, uchar null_bit_arg, bool is_nullable,
+                  enum utype unireg_check_arg, const char *field_name_arg,
+                  TABLE_SHARE *share, CHARSET_INFO *cs);
+  Field_timestamp(bool is_nullable, const char *field_name_arg,
+                  CHARSET_INFO *cs);
   enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;}
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
   enum Item_result cmp_type () const { return INT_RESULT; }
@@ -1290,10 +1283,10 @@ public:
 class Field_year :public Field_tiny {
 public:
   Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	     uchar null_bit_arg,
-	     enum utype unireg_check_arg, const char *field_name_arg)
-    :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-		unireg_check_arg, field_name_arg, 1, 1)
+             uchar null_bit_arg, bool is_nullable,
+             enum utype unireg_check_arg, const char *field_name_arg)
+    :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+                unireg_check_arg, field_name_arg, 1, 1)
     {}
   enum_field_types type() const { return MYSQL_TYPE_YEAR;}
   int  store(const char *to,uint length,CHARSET_INFO *charset);
@@ -1311,15 +1304,11 @@ public:
 class Field_date :public Field_str {
 public:
   Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
-	     enum utype unireg_check_arg, const char *field_name_arg,
-	     CHARSET_INFO *cs)
-    :Field_str(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg, cs)
+             bool is_nullable, enum utype unireg_check_arg,
+             const char *field_name_arg, CHARSET_INFO *cs)
+    :Field_str(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg, cs)
     { flags|= BINARY_FLAG; }
-  Field_date(bool maybe_null_arg, const char *field_name_arg,
-             CHARSET_INFO *cs)
-    :Field_str((uchar*) 0, MAX_DATE_WIDTH, maybe_null_arg ? (uchar*) "": 0,0,
-	       NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
   enum_field_types type() const { return MYSQL_TYPE_DATE;}
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
   enum Item_result cmp_type () const { return INT_RESULT; }
@@ -1359,14 +1348,14 @@ public:
 class Field_newdate :public Field_str {
 public:
   Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
-		enum utype unireg_check_arg, const char *field_name_arg,
-		CHARSET_INFO *cs)
-    :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg, cs)
+                bool is_nullable, enum utype unireg_check_arg,
+                const char *field_name_arg,	CHARSET_INFO *cs)
+    :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg, cs)
     { flags|= BINARY_FLAG; }
-  Field_newdate(bool maybe_null_arg, const char *field_name_arg,
+  Field_newdate(bool is_nullable, const char *field_name_arg,
                 CHARSET_INFO *cs)
-    :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
+    :Field_str((uchar*) 0,10, is_nullable ? (uchar*) "": 0,0, is_nullable,
                NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
   enum_field_types type() const { return MYSQL_TYPE_DATE;}
   enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; }
@@ -1399,14 +1388,14 @@ public:
 class Field_time :public Field_str {
 public:
   Field_time(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
-	     enum utype unireg_check_arg, const char *field_name_arg,
-	     CHARSET_INFO *cs)
-    :Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg, cs)
+             bool is_nullable, enum utype unireg_check_arg,
+             const char *field_name_arg, CHARSET_INFO *cs)
+    :Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg, cs)
     { flags|= BINARY_FLAG; }
-  Field_time(bool maybe_null_arg, const char *field_name_arg,
+  Field_time(bool is_nullable, const char *field_name_arg,
              CHARSET_INFO *cs)
-    :Field_str((uchar*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
+    :Field_str((uchar*) 0,8, is_nullable ? (uchar*) "": 0,0, is_nullable,
 	       NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
   enum_field_types type() const { return MYSQL_TYPE_TIME;}
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
@@ -1438,15 +1427,15 @@ public:
 class Field_datetime :public Field_str {
 public:
   Field_datetime(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
-		 enum utype unireg_check_arg, const char *field_name_arg,
-		 CHARSET_INFO *cs)
+                 bool is_nullable, enum utype unireg_check_arg,
+                 const char *field_name_arg, CHARSET_INFO *cs)
     :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg, cs)
+               is_nullable, unireg_check_arg, field_name_arg, cs)
     { flags|= BINARY_FLAG; }
-  Field_datetime(bool maybe_null_arg, const char *field_name_arg,
+  Field_datetime(bool is_nullable, const char *field_name_arg,
 		 CHARSET_INFO *cs)
-    :Field_str((uchar*) 0, MAX_DATETIME_WIDTH, maybe_null_arg ? (uchar*) "": 0,0,
-	       NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
+    :Field_str((uchar*) 0, MAX_DATETIME_WIDTH, is_nullable ? (uchar*) "": 0,0,
+	      is_nullable, NONE, field_name_arg, cs) { flags|= BINARY_FLAG; }
   enum_field_types type() const { return MYSQL_TYPE_DATETIME;}
 #ifdef HAVE_LONG_LONG
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
@@ -1496,17 +1485,17 @@ class Field_string :public Field_longstr
 public:
   bool can_alter_field_type;
   Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
-	       uchar null_bit_arg,
-	       enum utype unireg_check_arg, const char *field_name_arg,
-	       CHARSET_INFO *cs)
+               uchar null_bit_arg, bool is_nullable,
+               enum utype unireg_check_arg, const char *field_name_arg,
+               CHARSET_INFO *cs)
     :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-                   unireg_check_arg, field_name_arg, cs),
-     can_alter_field_type(1) {};
-  Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+                   is_nullable, unireg_check_arg, field_name_arg, cs),
+    can_alter_field_type(1) {};
+  Field_string(uint32 len_arg,bool is_nullable, const char *field_name_arg,
                CHARSET_INFO *cs)
-    :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
-                   NONE, field_name_arg, cs),
-     can_alter_field_type(1) {};
+    :Field_longstr((uchar*) 0, len_arg, is_nullable ? (uchar*) "": 0, 0,
+                   is_nullable, NONE, field_name_arg, cs),
+                   can_alter_field_type(1) {};
 
   enum_field_types type() const
   {
@@ -1576,20 +1565,20 @@ public:
   uint32 length_bytes;
   Field_varstring(uchar *ptr_arg,
                   uint32 len_arg, uint length_bytes_arg,
-                  uchar *null_ptr_arg, uchar null_bit_arg,
-		  enum utype unireg_check_arg, const char *field_name_arg,
-		  TABLE_SHARE *share, CHARSET_INFO *cs)
-    :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+                  uchar *null_ptr_arg, uchar null_bit_arg, bool is_nullable,
+                  enum utype unireg_check_arg, const char *field_name_arg,
+                  TABLE_SHARE *share, CHARSET_INFO *cs)
+    :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
                    unireg_check_arg, field_name_arg, cs),
      length_bytes(length_bytes_arg)
   {
     share->varchar_fields++;
   }
-  Field_varstring(uint32 len_arg,bool maybe_null_arg,
+  Field_varstring(uint32 len_arg,bool is_nullable,
                   const char *field_name_arg,
                   TABLE_SHARE *share, CHARSET_INFO *cs)
-    :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
-                   NONE, field_name_arg, cs),
+    :Field_longstr((uchar*) 0,len_arg, is_nullable ? (uchar*) "": 0, 0,
+                   is_nullable, NONE, field_name_arg, cs),
      length_bytes(len_arg < 256 ? 1 :2)
   {
     share->varchar_fields++;
@@ -1640,7 +1629,7 @@ public:
   Field *new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
   Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
                        uchar *new_ptr, uchar *new_null_ptr,
-                       uint new_null_bit);
+                       uint new_null_bit, bool is_nullable);
   uint is_equal(Create_field *new_field);
   void hash(ulong *nr, ulong *nr2);
 private:
@@ -1662,20 +1651,21 @@ protected:
   
 public:
   Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
-	     enum utype unireg_check_arg, const char *field_name_arg,
-	     TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs);
-  Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+             bool is_nullable, enum utype unireg_check_arg,
+             const char *field_name_arg, TABLE_SHARE *share,
+             uint blob_pack_length, CHARSET_INFO *cs);
+  Field_blob(uint32 len_arg,bool is_nullable, const char *field_name_arg,
              CHARSET_INFO *cs)
-    :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
-                   NONE, field_name_arg, cs),
+    :Field_longstr((uchar*) 0, len_arg, is_nullable ? (uchar*) "": 0, 0,
+                   is_nullable, NONE, field_name_arg, cs),
     packlength(4)
   {
     flags|= BLOB_FLAG;
   }
-  Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+  Field_blob(uint32 len_arg,bool is_nullable, const char *field_name_arg,
 	     CHARSET_INFO *cs, bool set_packlength)
-    :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
-                   NONE, field_name_arg, cs)
+    :Field_longstr((uchar*) 0,len_arg, is_nullable ? (uchar*) "": 0, 0,
+                   is_nullable, NONE, field_name_arg, cs)
   {
     flags|= BLOB_FLAG;
     packlength= 4;
@@ -1688,7 +1678,8 @@ public:
     }
   }
   Field_blob(uint32 packlength_arg)
-    :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info),
+    :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, TRUE,
+                   NONE, "temp", system_charset_info),
     packlength(packlength_arg) {}
   enum_field_types type() const { return MYSQL_TYPE_BLOB;}
   enum ha_base_keytype key_type() const
@@ -1827,15 +1818,16 @@ public:
   enum geometry_type geom_type;
 
   Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
-	     enum utype unireg_check_arg, const char *field_name_arg,
-	     TABLE_SHARE *share, uint blob_pack_length,
-	     enum geometry_type geom_type_arg)
-     :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, 
-                 field_name_arg, share, blob_pack_length, &my_charset_bin)
+             bool is_nullable, enum utype unireg_check_arg,
+             const char *field_name_arg, TABLE_SHARE *share,
+             uint blob_pack_length, enum geometry_type geom_type_arg)
+    :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, is_nullable,
+                unireg_check_arg, field_name_arg, share, blob_pack_length,
+                &my_charset_bin)
   { geom_type= geom_type_arg; }
-  Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+  Field_geom(uint32 len_arg,bool is_nullable, const char *field_name_arg,
 	     TABLE_SHARE *share, enum geometry_type geom_type_arg)
-    :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin)
+    :Field_blob(len_arg, is_nullable, field_name_arg, &my_charset_bin)
   { geom_type= geom_type_arg; }
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
   enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; }
@@ -1845,7 +1837,7 @@ public:
   int  store(longlong nr, bool unsigned_val);
   int  store_decimal(const my_decimal *);
   uint size_of() const { return sizeof(*this); }
-  int  reset(void) { return !maybe_null() || Field_blob::reset(); }
+  int  reset(void) { return !is_nullable() || Field_blob::reset(); }
   geometry_type get_geometry_type() { return geom_type; };
 };
 #endif /*HAVE_SPATIAL*/
@@ -1857,13 +1849,13 @@ protected:
 public:
   TYPELIB *typelib;
   Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-             uchar null_bit_arg,
+             uchar null_bit_arg, bool is_nullable,
              enum utype unireg_check_arg, const char *field_name_arg,
              uint packlength_arg,
              TYPELIB *typelib_arg,
              CHARSET_INFO *charset_arg)
-    :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-	       unireg_check_arg, field_name_arg, charset_arg),
+    :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, is_nullable,
+               unireg_check_arg, field_name_arg, charset_arg),
     packlength(packlength_arg),typelib(typelib_arg)
   {
       flags|=ENUM_FLAG;
@@ -1904,14 +1896,13 @@ private:
 class Field_set :public Field_enum {
 public:
   Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-	    uchar null_bit_arg,
-	    enum utype unireg_check_arg, const char *field_name_arg,
-	    uint32 packlength_arg,
-	    TYPELIB *typelib_arg, CHARSET_INFO *charset_arg)
+            uchar null_bit_arg, bool is_nullable,
+            enum utype unireg_check_arg, const char *field_name_arg,
+            uint32 packlength_arg,
+            TYPELIB *typelib_arg, CHARSET_INFO *charset_arg)
     :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
-		    unireg_check_arg, field_name_arg,
-                packlength_arg,
-                typelib_arg,charset_arg)
+                is_nullable, unireg_check_arg, field_name_arg,
+                packlength_arg, typelib_arg,charset_arg)
     {
       flags=(flags & ~ENUM_FLAG) | SET_FLAG;
     }
@@ -1948,8 +1939,9 @@ public:
   uint bit_len;       // number of 'uneven' high bits
   uint bytes_in_rec;
   Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-            uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg,
-            enum utype unireg_check_arg, const char *field_name_arg);
+            uchar null_bit_arg, bool is_nullable, uchar *bit_ptr_arg,
+            uchar bit_ofs_arg, enum utype unireg_check_arg,
+            const char *field_name_arg);
   enum_field_types type() const { return MYSQL_TYPE_BIT; }
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
   uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
@@ -2012,7 +2004,7 @@ public:
 
   Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
                        uchar *new_ptr, uchar *new_null_ptr,
-                       uint new_null_bit);
+                       uint new_null_bit, bool is_nullable);
   void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg)
   {
     bit_ptr= bit_ptr_arg;
@@ -2048,7 +2040,7 @@ private:
 class Field_bit_as_char: public Field_bit {
 public:
   Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
-                    uchar null_bit_arg,
+                    uchar null_bit_arg, bool is_nullable,
                     enum utype unireg_check_arg, const char *field_name_arg);
   enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
   uint size_of() const { return sizeof(*this); }
@@ -2152,6 +2144,7 @@ public:
   uchar *from_ptr,*to_ptr;
   uchar *from_null_ptr,*to_null_ptr;
   my_bool *null_row;
+  bool is_nullable;
   uint	from_bit,to_bit;
   uint from_length,to_length;
   Field *from_field,*to_field;

=== modified file 'sql/field_conv.cc'
--- a/sql/field_conv.cc	2010-04-19 12:09:44 +0000
+++ b/sql/field_conv.cc	2010-06-01 13:33:14 +0000
@@ -100,7 +100,7 @@ static void do_field_to_null_str(Copy_fi
 static void do_outer_field_to_null_str(Copy_field *copy)
 {
   if (*copy->null_row ||
-      (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
+      (copy->is_nullable && (*copy->from_null_ptr & copy->from_bit)))
   {
     bzero(copy->to_ptr,copy->from_length);
     copy->to_null_ptr[0]=1;			// Always bit 1
@@ -116,25 +116,13 @@ static void do_outer_field_to_null_str(C
 int
 set_field_to_null(Field *field)
 {
-  if (field->real_maybe_null())
+  field->reset();
+  field->set_temporary_nullable(TRUE);
+  if (field->real_is_nullable())
   {
     field->set_null();
-    field->reset();
-    return 0;
-  }
-  field->reset();
-  switch (field->table->in_use->count_cuted_fields) {
-  case CHECK_FIELD_WARN:
-    field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
-    /* fall through */
-  case CHECK_FIELD_IGNORE:
     return 0;
-  case CHECK_FIELD_ERROR_FOR_NULL:
-    if (!field->table->in_use->no_errors)
-      my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
-    return -1;
   }
-  DBUG_ASSERT(0); // impossible
   return -1;
 }
 
@@ -153,19 +141,17 @@ set_field_to_null(Field *field)
     0    Field could take 0 or an automatic conversion was used
   @retval
     -1   Field could not take NULL and no conversion was used.
-    If no_conversion was not set, an error message is printed
 */
 
 int
 set_field_to_null_with_conversions(Field *field, bool no_conversions)
 {
-  if (field->real_maybe_null())
+  if (field->real_is_nullable())
   {
     field->set_null();
     field->reset();
-    return 0;
   }
-  if (no_conversions)
+  else if (no_conversions)
     return -1;
 
   /*
@@ -173,30 +159,19 @@ set_field_to_null_with_conversions(Field
     when set to NULL (TIMESTAMP fields which allow setting to NULL
     are handled by first check).
   */
-  if (field->type() == MYSQL_TYPE_TIMESTAMP)
-  {
+  else if (field->type() == MYSQL_TYPE_TIMESTAMP)
     ((Field_timestamp*) field)->set_time();
-    return 0;					// Ok to set time to NULL
-  }
-  field->reset();
-  if (field == field->table->next_number_field)
+  else if (field == field->table->next_number_field ||
+           (field->table->s->found_next_number_field &&
+            field == field->table->field[field->table->s->found_next_number_field -
+                                         field->table->s->field]))
   {
+    field->reset();
     field->table->auto_increment_field_not_null= FALSE;
-    return 0;				  // field is set in fill_record()
-  }
-  switch (field->table->in_use->count_cuted_fields) {
-  case CHECK_FIELD_WARN:
-    field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1);
-    /* fall through */
-  case CHECK_FIELD_IGNORE:
-    return 0;
-  case CHECK_FIELD_ERROR_FOR_NULL:
-    if (!field->table->in_use->no_errors)
-      my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name);
-    return -1;
   }
-  DBUG_ASSERT(0); // impossible
-  return -1;
+  else
+    return set_field_to_null(field);
+  return 0;
 }
 
 
@@ -223,7 +198,7 @@ static void do_copy_null(Copy_field *cop
 static void do_outer_field_null(Copy_field *copy)
 {
   if (*copy->null_row ||
-      (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
+      (copy->is_nullable && (*copy->from_null_ptr & copy->from_bit)))
   {
     *copy->to_null_ptr|=copy->to_bit;
     copy->to_field->reset();
@@ -534,7 +509,8 @@ void Copy_field::set(uchar *to,Field *fr
   from_ptr=from->ptr;
   to_ptr=to;
   from_length=from->pack_length();
-  if (from->maybe_null())
+  is_nullable=from->real_is_nullable();
+  if (from->is_nullable())
   {
     from_null_ptr=from->null_ptr;
     from_bit=	  from->null_bit;
@@ -590,15 +566,16 @@ void Copy_field::set(Field *to,Field *fr
 
   // set up null handling
   from_null_ptr=to_null_ptr=0;
-  if (from->maybe_null())
+  is_nullable= from->real_is_nullable();
+  if (from->is_nullable())
   {
     from_null_ptr=	from->null_ptr;
     from_bit=		from->null_bit;
-    if (to_field->real_maybe_null())
+    if (to_field->real_is_nullable())
     {
       to_null_ptr=	to->null_ptr;
       to_bit=		to->null_bit;
-      if (from_null_ptr)
+      if (from->real_is_nullable())
 	do_copy=	do_copy_null;
       else
       {
@@ -616,7 +593,7 @@ void Copy_field::set(Field *to,Field *fr
         do_copy= do_copy_not_null;
     }
   }
-  else if (to_field->real_maybe_null())
+  else if (to_field->real_is_nullable())
   {
     to_null_ptr=	to->null_ptr;
     to_bit=		to->null_bit;

=== modified file 'sql/filesort.cc'
--- a/sql/filesort.cc	2010-04-29 20:33:06 +0000
+++ b/sql/filesort.cc	2010-06-01 13:33:14 +0000
@@ -759,7 +759,7 @@ static void make_sortkey(register SORTPA
     bool maybe_null=0;
     if ((field=sort_field->field))
     {						// Field
-      if (field->maybe_null())
+      if (field->is_nullable())
       {
 	if (field->is_null())
 	{
@@ -1464,7 +1464,7 @@ sortlength(THD *thd, SORT_FIELD *sortord
         *multi_byte_charset= 1;
         sortorder->length= cs->coll->strnxfrmlen(cs, sortorder->length);
       }
-      if (sortorder->field->maybe_null())
+      if (sortorder->field->is_nullable())
 	length++;				// Place for NULL marker
     }
     else
@@ -1579,7 +1579,7 @@ get_addon_fields(THD *thd, Field **ptabf
     if (field->flags & BLOB_FLAG)
       return 0;
     length+= field->max_packed_col_length(field->pack_length());
-    if (field->maybe_null())
+    if (field->is_nullable())
       null_fields++;
     fields++;
   } 
@@ -1601,7 +1601,7 @@ get_addon_fields(THD *thd, Field **ptabf
       continue;
     addonf->field= field;
     addonf->offset= length;
-    if (field->maybe_null())
+    if (field->is_nullable())
     {
       addonf->null_offset= null_fields/8;
       addonf->null_bit= 1<<(null_fields & 7);

=== modified file 'sql/ha_ndbcluster_cond.cc'
--- a/sql/ha_ndbcluster_cond.cc	2010-03-31 14:05:33 +0000
+++ b/sql/ha_ndbcluster_cond.cc	2010-06-01 13:33:14 +0000
@@ -1035,7 +1035,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
     {
       if (!value || !field) break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       DBUG_PRINT("info", ("Generating EQ filter"));
       if (filter->cmp(NdbScanFilter::COND_EQ, 
                       field->get_field_no(),
@@ -1049,7 +1050,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
     {
       if (!value || !field) break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       DBUG_PRINT("info", ("Generating NE filter"));
       if (filter->cmp(NdbScanFilter::COND_NE, 
                       field->get_field_no(),
@@ -1063,7 +1065,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
     {
       if (!value || !field) break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       if (a == field)
       {
         DBUG_PRINT("info", ("Generating LT filter")); 
@@ -1089,7 +1092,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
     {
       if (!value || !field) break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       if (a == field)
       {
         DBUG_PRINT("info", ("Generating LE filter")); 
@@ -1115,7 +1119,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
     {
       if (!value || !field) break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       if (a == field)
       {
         DBUG_PRINT("info", ("Generating GE filter")); 
@@ -1141,7 +1146,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
     {
       if (!value || !field) break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       if (a == field)
       {
         DBUG_PRINT("info", ("Generating GT filter"));
@@ -1170,7 +1176,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
           (value->qualification.value_type != Item::VARBIN_ITEM))
           break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       DBUG_PRINT("info", ("Generating LIKE filter: like(%d,%s,%d)", 
                           field->get_field_no(), value->get_val(), 
                           value->pack_length()));
@@ -1189,7 +1196,8 @@ ha_ndbcluster_cond::build_scan_filter_pr
           (value->qualification.value_type != Item::VARBIN_ITEM))
           break;
       // Save value in right format for the field type
-      value->save_in_field(field);
+      if (!value->save_in_field(field))
+        field->check_constraints();
       DBUG_PRINT("info", ("Generating NOTLIKE filter: notlike(%d,%s,%d)", 
                           field->get_field_no(), value->get_val(), 
                           value->pack_length()));

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2010-05-31 12:38:54 +0000
+++ b/sql/item.cc	2010-06-01 13:33:14 +0000
@@ -1063,6 +1063,8 @@ int Item::save_in_field_no_warnings(Fiel
   thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
   thd->count_cuted_fields= CHECK_FIELD_IGNORE;
   res= save_in_field(field, no_conversions);
+  if (!res)
+    res= field->check_constraints();
   thd->count_cuted_fields= tmp;
   dbug_tmp_restore_column_map(table->write_set, old_map);
   thd->variables.sql_mode= sql_mode;
@@ -2016,7 +2018,7 @@ Item_field::Item_field(THD *thd, Item_fi
 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->is_nullable();
   decimals= field->decimals();
   table_name= *field_par->table_name;
   field_name= field_par->field_name;
@@ -5207,38 +5209,38 @@ Field *Item::tmp_table_field_from_field_
     field= Field_new_decimal::create_from_item(this);
     break;
   case MYSQL_TYPE_TINY:
-    field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			  name, 0, unsigned_flag);
+    field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                          Field::NONE, name, 0, unsigned_flag);
     break;
   case MYSQL_TYPE_SHORT:
-    field= new Field_short((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			   name, 0, unsigned_flag);
+    field= new Field_short((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                           Field::NONE, name, 0, unsigned_flag);
     break;
   case MYSQL_TYPE_LONG:
-    field= new Field_long((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			  name, 0, unsigned_flag);
+    field= new Field_long((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                          Field::NONE, name, 0, unsigned_flag);
     break;
 #ifdef HAVE_LONG_LONG
   case MYSQL_TYPE_LONGLONG:
-    field= new Field_longlong((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			      name, 0, unsigned_flag);
+    field= new Field_longlong((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                              Field::NONE, name, 0, unsigned_flag);
     break;
 #endif
   case MYSQL_TYPE_FLOAT:
-    field= new Field_float((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			   name, decimals, 0, unsigned_flag);
+    field= new Field_float((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                           Field::NONE, name, decimals, 0, unsigned_flag);
     break;
   case MYSQL_TYPE_DOUBLE:
-    field= new Field_double((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			    name, decimals, 0, unsigned_flag);
+    field= new Field_double((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                            Field::NONE, name, decimals, 0, unsigned_flag);
     break;
   case MYSQL_TYPE_NULL:
     field= new Field_null((uchar*) 0, max_length, Field::NONE,
 			  name, &my_charset_bin);
     break;
   case MYSQL_TYPE_INT24:
-    field= new Field_medium((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			    name, 0, unsigned_flag);
+    field= new Field_medium((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                            Field::NONE, name, 0, unsigned_flag);
     break;
   case MYSQL_TYPE_NEWDATE:
   case MYSQL_TYPE_DATE:
@@ -5254,11 +5256,11 @@ Field *Item::tmp_table_field_from_field_
     field= new Field_datetime(maybe_null, name, &my_charset_bin);
     break;
   case MYSQL_TYPE_YEAR:
-    field= new Field_year((uchar*) 0, max_length, null_ptr, 0, Field::NONE,
-			  name);
+    field= new Field_year((uchar*) 0, max_length, null_ptr, 0, maybe_null,
+                          Field::NONE, name);
     break;
   case MYSQL_TYPE_BIT:
-    field= new Field_bit_as_char(NULL, max_length, null_ptr, 0,
+    field= new Field_bit_as_char(NULL, max_length, null_ptr, 0, maybe_null,
                                  Field::NONE, name);
     break;
   default:
@@ -7132,6 +7134,9 @@ bool Item_trigger_field::fix_fields(THD 
 
     field= (row_version == OLD_ROW) ? triggers->old_field[field_idx] :
                                       triggers->new_field[field_idx];
+    /* Allow new fields to temporarily store NULL during trigger processing. */
+    if (row_version == NEW_ROW)
+      field->set_temporary_nullable(TRUE);
     set_field(field);
     fixed= 1;
     return FALSE;
@@ -8123,7 +8128,7 @@ Field *Item_type_holder::make_field_by_t
   switch (fld_type) {
   case MYSQL_TYPE_ENUM:
     DBUG_ASSERT(enum_set_typelib);
-    field= new Field_enum((uchar *) 0, max_length, null_ptr, 0,
+    field= new Field_enum((uchar *) 0, max_length, null_ptr, 0, maybe_null,
                           Field::NONE, name,
                           get_enum_pack_length(enum_set_typelib->count),
                           enum_set_typelib, collation.collation);
@@ -8132,7 +8137,7 @@ Field *Item_type_holder::make_field_by_t
     return field;
   case MYSQL_TYPE_SET:
     DBUG_ASSERT(enum_set_typelib);
-    field= new Field_set((uchar *) 0, max_length, null_ptr, 0,
+    field= new Field_set((uchar *) 0, max_length, null_ptr, 0, maybe_null,
                          Field::NONE, name,
                          get_set_pack_length(enum_set_typelib->count),
                          enum_set_typelib, collation.collation);

=== modified file 'sql/item.h'
--- a/sql/item.h	2010-05-31 12:54:50 +0000
+++ b/sql/item.h	2010-06-01 13:33:14 +0000
@@ -587,7 +587,10 @@ public:
   int save_in_field_no_warnings(Field *field, bool no_conversions);
   virtual int save_in_field(Field *field, bool no_conversions);
   virtual void save_org_in_field(Field *field)
-  { (void) save_in_field(field, 1); }
+  {
+    if (!save_in_field(field, 1))
+      field->check_constraints();
+  }
   virtual int save_safe_in_field(Field *field)
   { return save_in_field(field, 1); }
   virtual bool send(Protocol *protocol, String *str);
@@ -1758,7 +1761,8 @@ public:
   bool is_result_field() { return result_field != 0; }
   void save_in_result_field(bool no_conversions)
   {
-    save_in_field(result_field, no_conversions);
+    if (!save_in_field(result_field, no_conversions))
+      result_field->check_constraints();
   }
   bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
 };  
@@ -2360,7 +2364,8 @@ public:
   bool is_result_field() { return 1; }
   void save_in_result_field(bool no_conversions)
   {
-    save_in_field(result_field, no_conversions);
+    if (!save_in_field(result_field, no_conversions))
+      result_field->check_constraints();
   }
   void cleanup();
   /*
@@ -2462,7 +2467,8 @@ public:
   bool is_result_field() { return 1; }
   void save_in_result_field(bool no_conversions)
   {
-    (*ref)->save_in_field(result_field, no_conversions);
+    if (!((*ref)->save_in_field(result_field, no_conversions)))
+      result_field->check_constraints();
   }
   Item *real_item()
   {

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2010-05-31 12:52:19 +0000
+++ b/sql/item_cmpfunc.cc	2010-06-01 13:33:14 +0000
@@ -433,7 +433,8 @@ static bool convert_constant_item(THD *t
                              !(field->table->status & STATUS_NO_RECORD)));
     if (save_field_value)
       orig_field_val= field->val_int();
-    if (!(*item)->is_null() && !(*item)->save_in_field(field, 1))
+    if (!(*item)->is_null() && !(*item)->save_in_field(field, 1) &&
+        !field->check_constraints())
     {
       Item *tmp= new Item_int_with_ref(field->val_int(), *item,
                                        test(field->flags & UNSIGNED_FLAG));

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2010-05-05 10:45:26 +0000
+++ b/sql/item_func.h	2010-06-01 13:33:14 +0000
@@ -1438,7 +1438,11 @@ public:
   {
     return save_in_field(field, no_conversions, 1);
   }
-  void save_org_in_field(Field *field) { (void)save_in_field(field, 1, 0); }
+  void save_org_in_field(Field *field)
+  {
+    if (!save_in_field(field, 1, 0))
+      field->check_constraints();
+  }
   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	2010-04-27 09:59:14 +0000
+++ b/sql/item_sum.cc	2010-06-01 13:33:14 +0000
@@ -1010,7 +1010,8 @@ bool Aggregator_distinct::add()
   }
   else
   {
-    item_sum->get_arg(0)->save_in_field(table->field[0], FALSE);
+    if (!item_sum->get_arg(0)->save_in_field(table->field[0], FALSE))
+      table->field[0]->check_constraints();
     if (table->field[0]->is_null())
       return 0;
     DBUG_ASSERT(tree);

=== modified file 'sql/key.cc'
--- a/sql/key.cc	2010-05-27 16:01:43 +0000
+++ b/sql/key.cc	2010-06-01 13:33:14 +0000
@@ -537,8 +537,8 @@ int key_rec_cmp(void *key_p, uchar *firs
       if (key_part->null_bit)
       {
         /* The key_part can contain NULL values */
-        bool first_is_null= field->is_null_in_record_with_offset(first_diff);
-        bool sec_is_null= field->is_null_in_record_with_offset(sec_diff);
+        bool first_is_null= field->is_real_null(first_diff);
+        bool sec_is_null= field->is_real_null(sec_diff);
         /*
           NULL is smaller then everything so if first is NULL and the other
           not then we know that we should return -1 and for the opposite

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2010-05-29 17:19:09 +0000
+++ b/sql/log_event.cc	2010-06-01 13:33:14 +0000
@@ -8155,7 +8155,7 @@ Table_map_log_event::Table_map_log_event
 
   bzero(m_null_bits, num_null_bytes);
   for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
-    if (m_table->field[i]->maybe_null())
+    if (m_table->field[i]->is_nullable())
       m_null_bits[(i / 8)]+= 1 << (i % 8);
 
 }

=== modified file 'sql/log_event_old.cc'
--- a/sql/log_event_old.cc	2010-05-24 19:01:36 +0000
+++ b/sql/log_event_old.cc	2010-06-01 13:33:14 +0000
@@ -445,7 +445,7 @@ copy_extra_record_fields(TABLE *table,
       /*
         Set the null bit according to the values in record[1]
        */
-      if ((*field_ptr)->maybe_null() &&
+      if ((*field_ptr)->is_nullable() &&
           (*field_ptr)->is_null_in_record(reinterpret_cast<uchar*>(table->record[1])))
         (*field_ptr)->set_null();
       else

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2010-05-11 08:27:53 +0000
+++ b/sql/opt_range.cc	2010-06-01 13:33:14 +0000
@@ -1691,7 +1691,7 @@ inline void SEL_ARG::make_root()
 
 SEL_ARG::SEL_ARG(Field *f,const uchar *min_value_arg,
                  const uchar *max_value_arg)
-  :min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_maybe_null()),
+  :min_flag(0), max_flag(0), maybe_flag(0), maybe_null(f->real_is_nullable()),
    elements(1), use_count(1), field(f), min_value((uchar*) min_value_arg),
    max_value((uchar*) max_value_arg), next(0),prev(0),
    next_key_part(0),color(BLACK),type(KEY_RANGE)
@@ -1703,7 +1703,7 @@ SEL_ARG::SEL_ARG(Field *field_,uint8 par
                  uchar *min_value_, uchar *max_value_,
 		 uint8 min_flag_,uint8 max_flag_,uint8 maybe_flag_)
   :min_flag(min_flag_),max_flag(max_flag_),maybe_flag(maybe_flag_),
-   part(part_),maybe_null(field_->real_maybe_null()), elements(1),use_count(1),
+   part(part_),maybe_null(field_->real_is_nullable()), elements(1),use_count(1),
    field(field_), min_value(min_value_), max_value(max_value_),
    next(0),prev(0),next_key_part(0),color(BLACK),type(KEY_RANGE)
 {
@@ -1794,7 +1794,7 @@ static int sel_cmp(Field *field, uchar *
   if (b_flag & (NO_MIN_RANGE | NO_MAX_RANGE))
     return (b_flag & NO_MIN_RANGE) ? 1 : -1;
 
-  if (field->real_maybe_null())			// If null is part of key
+  if (field->real_is_nullable())			// If null is part of key
   {
     if (*a != *b)
     {
@@ -2850,7 +2850,7 @@ void store_key_image_to_rec(Field *field
   /* Do the same as print_key() does */ 
   my_bitmap_map *old_map;
 
-  if (field->real_maybe_null())
+  if (field->real_is_nullable())
   {
     if (*ptr)
     {
@@ -5826,7 +5826,7 @@ static SEL_ARG *
 get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field,
             KEY_PART *key_part, Item_func::Functype type,Item *value)
 {
-  uint maybe_null=(uint) field->real_maybe_null();
+  uint maybe_null=(uint) field->real_is_nullable();
   bool optimize_range;
   SEL_ARG *tree= 0;
   MEM_ROOT *alloc= param->mem_root;
@@ -10773,7 +10773,7 @@ void QUICK_GROUP_MIN_MAX_SELECT::update_
     }
   }
   else if (have_min && min_max_arg_part &&
-           min_max_arg_part->field->real_maybe_null())
+           min_max_arg_part->field->real_is_nullable())
   {
     /*
       If a MIN/MAX argument value is NULL, we can quickly determine
@@ -11585,7 +11585,7 @@ print_key(KEY_PART *key_part, const ucha
     Field *field=      key_part->field;
     store_length= key_part->store_length;
 
-    if (field->real_maybe_null())
+    if (field->real_is_nullable())
     {
       if (*key)
       {

=== modified file 'sql/opt_sum.cc'
--- a/sql/opt_sum.cc	2010-05-23 20:41:18 +0000
+++ b/sql/opt_sum.cc	2010-06-01 13:33:14 +0000
@@ -157,7 +157,7 @@ static int get_index_min_value(TABLE *ta
          Check if case 1 from above holds. If it does, we should read
          the skipped tuple.
       */
-      if (item_field->field->real_maybe_null() &&
+      if (item_field->field->real_is_nullable() &&
           ref->key_buff[prefix_len] == 1 &&
           /*
             Last keypart (i.e. the argument to MIN) is set to NULL by
@@ -169,7 +169,7 @@ static int get_index_min_value(TABLE *ta
           (error == HA_ERR_KEY_NOT_FOUND ||
            key_cmp_if_same(table, ref->key_buff, ref->key, prefix_len)))
       {
-        DBUG_ASSERT(item_field->field->real_maybe_null());
+        DBUG_ASSERT(item_field->field->real_is_nullable());
         error= table->file->index_read_map(table->record[0],
                                            ref->key_buff,
                                            make_prev_keypart_map(ref->key_parts),

=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc	2010-05-31 12:38:54 +0000
+++ b/sql/partition_info.cc	2010-06-01 13:33:14 +0000
@@ -2042,6 +2042,7 @@ bool partition_info::fix_column_value_fu
         save_got_warning= thd->got_warning;
         thd->got_warning= 0;
         if (column_item->save_in_field(field, TRUE) ||
+            field->check_constraints() ||
             thd->got_warning)
         {
           my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));

=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc	2010-04-01 19:34:09 +0000
+++ b/sql/rpl_record.cc	2010-06-01 13:33:14 +0000
@@ -261,7 +261,7 @@ unpack_row(Relay_log_info const *rli,
 
       if (null_bits & null_mask)
       {
-        if (f->maybe_null())
+        if (f->is_nullable())
         {
           DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x",
                                null_mask, null_bits));

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2010-05-29 17:19:09 +0000
+++ b/sql/sp_head.cc	2010-06-01 13:33:14 +0000
@@ -375,7 +375,8 @@ sp_eval_expr(THD *thd, Field *result_fie
 
   /* Save the value in the field. Convert the value if needed. */
 
-  expr_item->save_in_field(result_field, 0);
+  if (!expr_item->save_in_field(result_field, 0))
+    result_field->check_constraints();
 
   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	2010-05-28 05:49:57 +0000
+++ b/sql/sql_base.cc	2010-06-01 13:33:14 +0000
@@ -5989,16 +5989,21 @@ Field *
 find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
                     bool allow_rowid, uint *cached_field_index_ptr)
 {
-  Field **field_ptr, *field;
+  Field **field_ptr, *field, **table_field;
   uint cached_field_index= *cached_field_index_ptr;
   DBUG_ENTER("find_field_in_table");
   DBUG_PRINT("enter", ("table: '%s', field name: '%s'", table->alias, name));
 
+  if (thd->mark_used_columns == MARK_COLUMNS_WRITE && table->nullable_field)
+    table_field= table->nullable_field;
+  else
+    table_field= table->field;
+
   /* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
   if (cached_field_index < table->s->fields &&
       !my_strcasecmp(system_charset_info,
                      table->field[cached_field_index]->field_name, name))
-    field_ptr= table->field + cached_field_index;
+    field_ptr= table_field + cached_field_index;
   else if (table->s->name_hash.records)
   {
     field_ptr= (Field**) my_hash_search(&table->s->name_hash, (uchar*) name,
@@ -6009,12 +6014,12 @@ find_field_in_table(THD *thd, TABLE *tab
         field_ptr points to field in TABLE_SHARE. Convert it to the matching
         field in table
       */
-      field_ptr= (table->field + (field_ptr - table->s->field));
+      field_ptr= (table_field + (field_ptr - table->s->field));
     }
   }
   else
   {
-    if (!(field_ptr= table->field))
+    if (!(field_ptr= table_field))
       DBUG_RETURN((Field *)0);
     for (; *field_ptr; ++field_ptr)
       if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
@@ -6023,7 +6028,7 @@ find_field_in_table(THD *thd, TABLE *tab
 
   if (field_ptr && *field_ptr)
   {
-    *cached_field_index_ptr= field_ptr - table->field;
+    *cached_field_index_ptr= field_ptr - table_field;
     field= *field_ptr;
   }
   else
@@ -6032,7 +6037,7 @@ find_field_in_table(THD *thd, TABLE *tab
         my_strcasecmp(system_charset_info, name, "_rowid") ||
         table->s->rowid_field_offset == 0)
       DBUG_RETURN((Field*) 0);
-    field= table->field[table->s->rowid_field_offset-1];
+    field= table_field[table->s->rowid_field_offset-1];
   }
 
   update_field_dependencies(thd, field, table);
@@ -8263,6 +8268,40 @@ err:
 
 
 /*
+  Check that field values does not break constraints.
+
+  SYNOPSIS
+    check_record()
+    thd           thread handler
+    fields        Item_fields list to be checked
+    ignore_errors TRUE if we should ignore errors
+
+  RETURN
+    FALSE   OK
+    TRUE    error occured
+*/
+
+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->filed_for_view_update();
+    if (field->field->check_constraints() && !ignore_errors)
+    {
+      my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
+      return TRUE;
+    }
+  }
+  return thd->is_error();
+}
+
+
+/*
   Fill fields in list with values from the list of items and invoke
   before triggers.
 
@@ -8291,9 +8330,17 @@ fill_record_n_invoke_before_triggers(THD
                                      Table_triggers_list *triggers,
                                      enum trg_event_type event)
 {
-  return (fill_record(thd, fields, values, ignore_errors) ||
-          (triggers && triggers->process_triggers(thd, event,
-                                                 TRG_ACTION_BEFORE, TRUE)));
+  bool error_fill= fill_record(thd, fields, values, ignore_errors);
+  if (!error_fill)
+    error_fill= (triggers &&
+                 triggers->process_triggers(thd, event,
+                                            TRG_ACTION_BEFORE, TRUE));
+  /*
+    We have to call check_record even if fill_record failed in order
+    to revert any illegal values (such as NULL in NOT NULL fields).
+  */
+  bool error_check= check_record(thd, fields, ignore_errors);
+  return (error_fill || error_check);
 }
 
 
@@ -8358,6 +8405,31 @@ err:
 
 
 /*
+  Check that field values does not break constraints.
+
+  SYNOPSIS
+    check_record()
+    thd           thread handler
+    ptr           pointer on pointer to record
+
+  RETURN
+    FALSE   OK
+    TRUE    error occured
+*/
+
+bool
+check_record(THD *thd, Field **ptr)
+{
+  Field *field;
+  while ((field = *ptr++) && !thd->is_error())
+  {
+    if (field->check_constraints())
+      return TRUE;
+  }
+  return thd->is_error();
+}
+
+/*
   Fill fields in array with values from the list of items and invoke
   before triggers.
 
@@ -8386,9 +8458,17 @@ fill_record_n_invoke_before_triggers(THD
                                      Table_triggers_list *triggers,
                                      enum trg_event_type event)
 {
-  return (fill_record(thd, ptr, values, ignore_errors) ||
-          (triggers && triggers->process_triggers(thd, event,
-                                                 TRG_ACTION_BEFORE, TRUE)));
+  bool error_fill= fill_record(thd, ptr, values, ignore_errors);
+  if (!error_fill)
+    error_fill= (triggers &&
+                 triggers->process_triggers(thd, event,
+                                            TRG_ACTION_BEFORE, TRUE));
+  /*
+    We have to call check_record even if fill_record failed in order
+    to revert any illegal values (such as NULL in NOT NULL fields).
+  */
+  bool error_check= check_record(thd, ptr);
+  return (error_fill || error_check);
 }
 
 

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2010-05-28 05:49:57 +0000
+++ b/sql/sql_base.h	2010-06-01 13:33:14 +0000
@@ -155,6 +155,7 @@ bool setup_fields(THD *thd, Item** ref_p
                   List<Item> *sum_func_list, bool allow_sum_func);
 bool fill_record(THD *thd, Field **field, List<Item> &values,
                  bool ignore_errors);
+bool check_record(THD *thd, Field **field);
 
 Field *
 find_field_in_tables(THD *thd, Item_ident *item,

=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc	2010-03-31 14:05:33 +0000
+++ b/sql/sql_handler.cc	2010-06-01 13:33:14 +0000
@@ -697,7 +697,8 @@ retry:
 	  goto err;
         }
         old_map= dbug_tmp_use_all_columns(table, table->write_set);
-	(void) item->save_in_field(key_part->field, 1);
+        if (!item->save_in_field(key_part->field, 1))
+          key_part->field->check_constraints();
         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	2010-05-20 12:41:01 +0000
+++ b/sql/sql_insert.cc	2010-06-01 13:33:14 +0000
@@ -839,7 +839,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
             share->default_values[share->null_bytes - 1];
         }
       }
-      if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0,
+      if (fill_record_n_invoke_before_triggers(thd, table->nullable_field, *values, 0,
                                                table->triggers,
                                                TRG_EVENT_INSERT))
       {
@@ -2119,7 +2119,8 @@ TABLE *Delayed_insert::get_local_table(T
   Field **field,**org_field, *found_next_number_field;
   TABLE *copy;
   TABLE_SHARE *share;
-  uchar *bitmap;
+  uchar *bitmap, *extra_null_ptr;
+  uint extra_null_bytes, extra_null_bit_pos;
   DBUG_ENTER("Delayed_insert::get_local_table");
 
   /* First request insert thread to get a lock */
@@ -2161,16 +2162,18 @@ TABLE *Delayed_insert::get_local_table(T
   share= table->s;
 
   /*
-    Allocate memory for the TABLE object, the field pointers array, and
+    Allocate memory for the TABLE object, the field pointers arrays, and
     one record buffer of reclength size. Normally a table has three
     record buffers of rec_buff_length size, which includes alignment
     bytes. Since the table copy is used for creating one record only,
     the other record buffers and alignment are unnecessary.
   */
   thd_proc_info(client_thd, "allocating local table");
+  // Extra bytes to temporarily store null_bits for NOT NULL fields
+  extra_null_bytes= (share->fields - share->null_fields + 7) / 8;
   copy= (TABLE*) client_thd->alloc(sizeof(*copy)+
-				   (share->fields+1)*sizeof(Field**)+
-				   share->reclength +
+                                   (2*(share->fields+1))*sizeof(Field**)+
+                                   share->reclength + extra_null_bytes +
                                    share->column_bitmap_size*2);
   if (!copy)
     goto error;
@@ -2180,9 +2183,12 @@ TABLE *Delayed_insert::get_local_table(T
   /* We don't need to change the file handler here */
   /* Assign the pointers for the field pointers array and the record. */
   field= copy->field= (Field**) (copy + 1);
-  bitmap= (uchar*) (field + share->fields + 1);
+  bitmap= (uchar*) (field + 2*(share->fields + 1));
   copy->record[0]= (bitmap + share->column_bitmap_size * 2);
   memcpy((char*) copy->record[0], (char*) table->record[0], share->reclength);
+  extra_null_ptr= copy->record[0] + share->reclength;
+  bzero(extra_null_ptr, extra_null_bytes);
+  extra_null_bit_pos= 0;
   /*
     Make a copy of all fields.
     The copied fields need to point into the copied record. This is done
@@ -2198,6 +2204,39 @@ TABLE *Delayed_insert::get_local_table(T
       goto error;
     (*field)->orig_table= copy;			// Remove connection
     (*field)->move_field_offset(adjust_ptrs);	// Point at copy->record[0]
+    if (!(*field)->real_is_nullable())
+    {
+      (*field)->null_ptr= extra_null_ptr;
+      (*field)->null_bit= ((uchar) 1) << extra_null_bit_pos;
+      if (++extra_null_bit_pos == 8)
+      {
+        extra_null_bit_pos= 0;
+        extra_null_ptr++;
+      }
+    }
+    if (*org_field == found_next_number_field)
+      (*field)->table->found_next_number_field= *field;
+  }
+  *field=0;
+  copy->nullable_field= ++field;
+  extra_null_ptr= copy->record[0] + share->reclength;
+  extra_null_bit_pos= 0;
+  for (org_field= table->nullable_field; *org_field; org_field++, field++)
+  {
+    if (!(*field= (*org_field)->new_field(client_thd->mem_root, copy, 1)))
+      goto error;
+    (*field)->orig_table= copy;			// Remove connection
+    (*field)->move_field_offset(adjust_ptrs);	// Point at copy->record[0]
+    if (!(*field)->real_is_nullable())
+    {
+      (*field)->null_ptr= extra_null_ptr;
+      (*field)->null_bit= ((uchar) 1) << extra_null_bit_pos;
+      if (++extra_null_bit_pos == 8)
+      {
+        extra_null_bit_pos= 0;
+        extra_null_ptr++;
+      }
+    }
     if (*org_field == found_next_number_field)
       (*field)->table->found_next_number_field= *field;
   }
@@ -3318,7 +3357,7 @@ void select_insert::store_values(List<It
     fill_record_n_invoke_before_triggers(thd, *fields, values, 1,
                                          table->triggers, TRG_EVENT_INSERT);
   else
-    fill_record_n_invoke_before_triggers(thd, table->field, values, 1,
+    fill_record_n_invoke_before_triggers(thd, table->nullable_field, values, 1,
                                          table->triggers, TRG_EVENT_INSERT);
 }
 

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2010-05-31 12:38:54 +0000
+++ b/sql/sql_load.cc	2010-06-01 13:33:14 +0000
@@ -252,7 +252,7 @@ int mysql_load(THD *thd,sql_exchange *ex
   if (!fields_vars.elements)
   {
     Field **field;
-    for (field=table->field; *field ; field++)
+    for (field=table->nullable_field; *field ; field++)
       fields_vars.push_back(new Item_field(*field));
     bitmap_set_all(table->write_set);
     table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
@@ -821,7 +821,7 @@ read_fixed_length(THD *thd, COPY_INFO &i
                             ER_WARN_TOO_FEW_RECORDS,
                             ER(ER_WARN_TOO_FEW_RECORDS),
                             thd->warning_info->current_row_for_warning());
-        if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
+        if (!field->is_nullable() && field->type() == FIELD_TYPE_TIMESTAMP)
             ((Field_timestamp*) field)->set_time();
       }
       else
@@ -952,7 +952,7 @@ read_sep_field(THD *thd, COPY_INFO &info
             DBUG_RETURN(1);
           }
           field->set_null();
-          if (!field->maybe_null())
+          if (!field->is_nullable())
           {
             if (field->type() == MYSQL_TYPE_TIMESTAMP)
               ((Field_timestamp*) field)->set_time();
@@ -1019,7 +1019,7 @@ read_sep_field(THD *thd, COPY_INFO &info
                      thd->warning_info->current_row_for_warning());
             DBUG_RETURN(1);
           }
-          if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
+          if (!field->is_nullable() && field->type() == FIELD_TYPE_TIMESTAMP)
               ((Field_timestamp*) field)->set_time();
           /*
             QQ: We probably should not throw warning for each field.
@@ -1157,7 +1157,7 @@ read_xml_field(THD *thd, COPY_INFO &info
           field->set_null();
           if (field == table->next_number_field)
             table->auto_increment_field_not_null= TRUE;
-          if (!field->maybe_null())
+          if (!field->is_nullable())
           {
             if (field->type() == FIELD_TYPE_TIMESTAMP)
               ((Field_timestamp *) field)->set_time();

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2010-05-28 05:49:57 +0000
+++ b/sql/sql_partition.cc	2010-06-01 13:33:14 +0000
@@ -2909,7 +2909,7 @@ static void copy_to_part_field_buffers(F
   {
     *restore_ptr= field->ptr;
     restore_ptr++;
-    if (!field->maybe_null() || !field->is_null())
+    if (!field->is_nullable() || !field->is_null())
     {
       CHARSET_INFO *cs= ((Field_str*)field)->charset();
       uint max_len= field->pack_length();
@@ -7060,7 +7060,7 @@ uint32 store_tuple_to_record(Field **pfi
   while (value < value_end)
   {
     loc_value= value;
-    if ((*pfield)->real_maybe_null())
+    if ((*pfield)->real_is_nullable())
     {
       if (*loc_value)
         (*pfield)->set_null();
@@ -7377,7 +7377,7 @@ int get_part_iter_for_interval_via_mappi
     Find minimum: Do special handling if the interval has left bound in form
      " NULL <= X ":
   */
-  if (field->real_maybe_null() && part_info->has_null_value && 
+  if (field->real_is_nullable() && part_info->has_null_value && 
       !(flags & (NO_MIN_RANGE | NEAR_MIN)) && *min_value)
   {
     part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
@@ -7508,7 +7508,7 @@ int get_part_iter_for_interval_via_walki
   }
 
   /* Handle the "t.field IS NULL" interval, it is a special case */
-  if (field->real_maybe_null() && !(flags & (NO_MIN_RANGE | NO_MAX_RANGE)) &&
+  if (field->real_is_nullable() && !(flags & (NO_MIN_RANGE | NO_MAX_RANGE)) &&
       *min_value && *max_value)
   {
     /* 
@@ -7542,7 +7542,7 @@ int get_part_iter_for_interval_via_walki
     DBUG_RETURN(0); /* No partitions match */
   }
 
-  if ((field->real_maybe_null() && 
+  if ((field->real_is_nullable() && 
        ((!(flags & NO_MIN_RANGE) && *min_value) ||  // NULL <? X
         (!(flags & NO_MAX_RANGE) && *max_value))) ||  // X <? NULL
       (flags & (NO_MIN_RANGE | NO_MAX_RANGE)))    // -inf at any bound
@@ -7823,7 +7823,7 @@ uint get_partition_field_store_length(Fi
   uint store_length;
 
   store_length= field->key_length();
-  if (field->real_maybe_null())
+  if (field->real_is_nullable())
     store_length+= HA_KEY_NULL_LENGTH;
   if (field->real_type() == MYSQL_TYPE_VARCHAR)
     store_length+= HA_KEY_BLOB_LENGTH;

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-05-28 05:49:57 +0000
+++ b/sql/sql_select.cc	2010-06-01 13:33:14 +0000
@@ -583,7 +583,7 @@ JOIN::prepare(Item ***rref_pointer_array
       */
       if (!real_order &&
           (item->type() != Item::FIELD_ITEM ||
-           ((Item_field *) item)->field->maybe_null() ||
+           ((Item_field *) item)->field->is_nullable() ||
            ((Item_field *) item)->field->sort_length()))
         real_order= TRUE;
 
@@ -3252,7 +3252,7 @@ add_key_field(KEY_FIELD **key_fields,uin
   {
     // Don't remove column IS NULL on a LEFT JOIN table
     if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
-        !field->table->maybe_null || field->null_ptr)
+        !field->table->maybe_null || field->real_is_nullable())
       return;					// Not a key. Skip it
     exists_optimize= KEY_OPTIMIZE_EXISTS;
     DBUG_ASSERT(num_values == 1);
@@ -3272,7 +3272,7 @@ add_key_field(KEY_FIELD **key_fields,uin
     if (!(usable_tables & field->table->map))
     {
       if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
-          !field->table->maybe_null || field->null_ptr)
+          !field->table->maybe_null || field->real_is_nullable())
 	return;					// Can't use left join optimize
       exists_optimize= KEY_OPTIMIZE_EXISTS;
     }
@@ -3384,7 +3384,7 @@ add_key_field(KEY_FIELD **key_fields,uin
   (*key_fields)->null_rejecting= ((cond->functype() == Item_func::EQ_FUNC ||
                                    cond->functype() == Item_func::MULT_EQUAL_FUNC) &&
                                   ((*value)->type() == Item::FIELD_ITEM) &&
-                                  ((Item_field*)*value)->field->maybe_null());
+                                  ((Item_field*)*value)->field->is_nullable());
   (*key_fields)->cond_guard= NULL;
   (*key_fields)++;
 }
@@ -3933,7 +3933,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_AR
         return TRUE;
       /* Mark that we can optimize LEFT JOIN */
       if (field->val->type() == Item::NULL_ITEM &&
-	  !field->field->real_maybe_null())
+	  !field->field->real_is_nullable())
 	field->field->table->reginfo.not_exists_optimize=1;
     }
   }
@@ -5475,7 +5475,7 @@ static void calc_used_field_length(THD *
       rec_length+=field->pack_length();
       if (flags & BLOB_FLAG)
 	blobs++;
-      if (!(flags & NOT_NULL_FLAG))
+      if (field->real_is_nullable())
 	null_fields++;
     }
   }
@@ -5879,6 +5879,8 @@ store_val_in_field(Field *field, Item *i
   enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
   thd->count_cuted_fields= check_flag;
   error= item->save_in_field(field, 1);
+  if (!error)
+    error= field->check_constraints();
   thd->count_cuted_fields= old_count_cuted_fields;
   dbug_tmp_restore_column_map(table->write_set, old_map);
   return error || cuted_fields != thd->cuted_fields;
@@ -7522,7 +7524,7 @@ static bool check_simple_equality(Item *
 
     /* As (NULL=NULL) != TRUE we can't just remove the predicate f=f */
     if (left_field->eq(right_field)) /* f = f */
-      return (!(left_field->maybe_null() && !left_item_equal)); 
+      return (!(left_field->is_nullable() && !left_item_equal)); 
 
     if (left_item_equal && left_item_equal == right_item_equal)
     {
@@ -9316,7 +9318,7 @@ internal_remove_eq_conds(THD *thd, COND 
       */
       if (((field->type() == MYSQL_TYPE_DATE) ||
            (field->type() == MYSQL_TYPE_DATETIME)) &&
-          (field->flags & NOT_NULL_FLAG) && !field->table->maybe_null)
+          !field->real_is_nullable() && !field->table->maybe_null)
       {
 	COND *new_cond;
 	if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2))))
@@ -9569,7 +9571,7 @@ Field *create_tmp_field_from_field(THD *
   if (convert_blob_length && convert_blob_length <= Field_varstring::MAX_SIZE &&
       (org_field->flags & BLOB_FLAG))
     new_field= new Field_varstring(convert_blob_length,
-                                   org_field->maybe_null(),
+                                   org_field->is_nullable(),
                                    org_field->field_name, table->s,
                                    org_field->charset());
   else
@@ -9584,7 +9586,7 @@ Field *create_tmp_field_from_field(THD *
     else
       new_field->field_name= name;
     new_field->flags|= (org_field->flags & NO_DEFAULT_VALUE_FLAG);
-    if (org_field->maybe_null() || (item && item->maybe_null))
+    if (org_field->is_nullable() || (item && item->maybe_null))
       new_field->flags&= ~NOT_NULL_FLAG;	// Because of outer join
     if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
         org_field->type() == MYSQL_TYPE_VARCHAR)
@@ -9798,7 +9800,7 @@ Field *create_tmp_field(THD *thd, TABLE 
       If item have to be able to store NULLs but underlaid field can't do it,
       create_tmp_field_from_field() can't be used for tmp field creation.
     */
-    if (field->maybe_null && !field->field->maybe_null())
+    if (field->maybe_null && !field->field->is_nullable())
     {
       result= create_tmp_field_from_item(thd, item, table, NULL,
                                          modify_item, convert_blob_length);
@@ -10180,7 +10182,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARA
           thd->mem_root= mem_root_save;
           arg= sum_item->set_arg(i, thd, new Item_field(new_field));
           thd->mem_root= &table->mem_root;
-	  if (!(new_field->flags & NOT_NULL_FLAG))
+          if (new_field->real_is_nullable())
           {
 	    null_count++;
             /*
@@ -10228,7 +10230,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARA
 	((Item_sum *) item)->result_field= new_field;
       tmp_from_field++;
       reclength+=new_field->pack_length();
-      if (!(new_field->flags & NOT_NULL_FLAG))
+      if (new_field->real_is_nullable())
 	null_count++;
       if (new_field->type() == MYSQL_TYPE_BIT)
         total_uneven_bit_length+= new_field->field_length & 7;
@@ -10363,7 +10365,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARA
     uint length;
     bzero((uchar*) recinfo,sizeof(*recinfo));
 
-    if (!(field->flags & NOT_NULL_FLAG))
+    if (field->real_is_nullable())
     {
       if (field->flags & GROUP_FLAG && !using_unique_constraint)
       {
@@ -10506,10 +10508,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARA
       {
 	cur_group->buff=(char*) group_buff;
 	if (!(cur_group->field= field->new_key_field(thd->mem_root,table,
-                                                     group_buff +
-                                                     test(maybe_null),
-                                                     field->null_ptr,
-                                                     field->null_bit)))
+                                               group_buff +
+                                               test(maybe_null),
+                                               field->null_ptr,
+                                               field->null_bit,
+                                               field->real_is_nullable())))
 	  goto err; /* purecov: inspected */
 	if (maybe_null)
 	{
@@ -10574,7 +10577,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARA
       key_part_info->field= new Field_string(table->record[0],
                                              (uint32) key_part_info->length,
                                              (uchar*) 0,
-                                             (uint) 0,
+                                             (uint) 0, FALSE,
                                              Field::NONE,
                                              NullS, &my_charset_bin);
       if (!key_part_info->field)
@@ -10696,7 +10699,7 @@ TABLE *create_virtual_tmp_table(THD *thd
       goto error;
     (*field)->init(table);
     record_length+= (*field)->pack_length();
-    if (! ((*field)->flags & NOT_NULL_FLAG))
+    if ((*field)->real_is_nullable())
       null_count++;
 
     if ((*field)->flags & BLOB_FLAG)
@@ -10732,7 +10735,7 @@ TABLE *create_virtual_tmp_table(THD *thd
     for (field= table->field; *field; ++field)
     {
       Field *cur_field= *field;
-      if ((cur_field->flags & NOT_NULL_FLAG))
+      if (!cur_field->real_is_nullable())
         cur_field->move_field(field_pos);
       else
       {
@@ -10855,7 +10858,7 @@ static bool create_myisam_tmp_table(TABL
 	    keyinfo->key_part[i].length > 4)
 	  seg->flag|= HA_SPACE_PACK;
       }
-      if (!(field->flags & NOT_NULL_FLAG))
+      if (field->real_is_nullable())
       {
 	seg->null_bit= field->null_bit;
 	seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
@@ -13252,7 +13255,7 @@ list_contains_unique_index(TABLE *table,
            key_part < key_part_end;
            key_part++)
       {
-        if (key_part->field->maybe_null() || 
+        if (key_part->field->is_nullable() || 
             !find_func(key_part->field, data))
           break;
       }
@@ -14380,7 +14383,7 @@ join_init_cache(THD *thd,JOIN_TAB *table
 	length+=field->fill_cache_field(copy);
 	if (copy->type == CACHE_BLOB)
 	  (*blob_ptr++)=copy;
-	if (field->real_maybe_null())
+	if (field->real_is_nullable())
 	  null_fields++;
         if (field->type() == MYSQL_TYPE_BIT &&
             ((Field_bit*)field)->bit_len)
@@ -14485,7 +14488,7 @@ store_record_in_cache(JOIN_CACHE *cache)
       {
 	uchar *str,*end;
         Field *field= copy->field;
-        if (field && field->maybe_null() && field->is_null())
+        if (field && field->is_nullable() && field->is_null())
           end= str= copy->str;
         else
           for (str=copy->str,end= str+copy->length;

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2010-05-27 06:46:44 +0000
+++ b/sql/sql_select.h	2010-06-01 13:33:14 +0000
@@ -647,14 +647,14 @@ public:
         Key segments are always packed with a 2 byte length prefix.
         See mi_rkey for details.
       */
-      to_field= new Field_varstring(ptr, length, 2, null, 1, 
+      to_field= new Field_varstring(ptr, length, 2, null, 1, null != NULL,
                                     Field::NONE, field_arg->field_name,
                                     field_arg->table->s, field_arg->charset());
       to_field->init(field_arg->table);
     }
     else
       to_field=field_arg->new_key_field(thd->mem_root, field_arg->table,
-                                        ptr, null, 1);
+                                        ptr, null, 1, null != NULL);
   }
   virtual ~store_key() {}			/** Not actually needed */
   virtual const char *name() const=0;
@@ -701,7 +701,7 @@ class store_key_field: public store_key
                   uchar *null_ptr_arg,
 		  uint length, Field *from_field, const char *name_arg)
     :store_key(thd, to_field_arg,ptr,
-	       null_ptr_arg ? null_ptr_arg : from_field->maybe_null() ? &err
+	       null_ptr_arg ? null_ptr_arg : from_field->is_nullable() ? &err
 	       : (uchar*) 0, length), field_name(name_arg)
   {
     if (to_field)
@@ -745,6 +745,8 @@ public:
     my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
                                                      table->write_set);
     int res= item->save_in_field(to_field, 1);
+    if (!res)
+      res= to_field->check_constraints();
     /*
      Item::save_in_field() may call Item::val_xxx(). And if this is a subquery
      we need to check for errors executing it and react accordingly
@@ -783,7 +785,10 @@ protected:  
       TABLE *table= to_field->table;
       my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
                                                        table->write_set);
-      if ((res= item->save_in_field(to_field, 1)))
+      res= item->save_in_field(to_field, 1);
+      if (!res)
+        res= to_field->check_constraints();
+      if (res)
       {       
         if (!err)
           err= res < 0 ? 1 : res; /* 1=STORE_KEY_FATAL */

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2010-05-28 05:49:57 +0000
+++ b/sql/sql_show.cc	2010-06-01 13:33:14 +0000
@@ -1079,7 +1079,7 @@ static bool get_field_default_value(THD 
       else if (quoted)
         def_value->append(STRING_WITH_LEN("''"));
     }
-    else if (field->maybe_null() && quoted)
+    else if (field->is_nullable() && quoted)
       def_value->append(STRING_WITH_LEN("NULL"));    // Null as default
     else
       return 0;
@@ -1189,6 +1189,9 @@ int store_create_info(THD *thd, TABLE_LI
   */
   old_map= tmp_use_all_columns(table, table->read_set);
 
+  Field *timestamp_field= table->timestamp_field;
+  if (timestamp_field)
+    timestamp_field= table->field[share->timestamp_field_offset];
   for (ptr=table->field ; (field= *ptr); ptr++)
   {
     uint flags = field->flags;
@@ -1227,7 +1230,7 @@ int store_create_info(THD *thd, TABLE_LI
       }
     }
 
-    if (flags & NOT_NULL_FLAG)
+    if (!field->real_is_nullable())
       packet->append(STRING_WITH_LEN(" NOT NULL"));
     else if (field->type() == MYSQL_TYPE_TIMESTAMP)
     {
@@ -1238,14 +1241,14 @@ int store_create_info(THD *thd, TABLE_LI
       packet->append(STRING_WITH_LEN(" NULL"));
     }
 
-    if (get_field_default_value(thd, table->timestamp_field,
+    if (get_field_default_value(thd, timestamp_field,
                                 field, &def_value, 1))
     {
       packet->append(STRING_WITH_LEN(" DEFAULT "));
       packet->append(def_value.ptr(), def_value.length(), system_charset_info);
     }
 
-    if (!limited_mysql_mode && table->timestamp_field == field && 
+    if (!limited_mysql_mode && timestamp_field == field && 
         field->unireg_check != Field::TIMESTAMP_DN_FIELD)
       packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
 
@@ -4060,6 +4063,8 @@ static int get_schema_column_record(THD 
   count= 0;
   ptr= show_table->field;
   timestamp_field= show_table->timestamp_field;
+  if (timestamp_field)
+    timestamp_field= show_table->field[show_table->s->timestamp_field_offset];
   show_table->use_all_columns();               // Required for default
   restore_record(show_table, s->default_values);
 
@@ -4115,7 +4120,7 @@ static int get_schema_column_record(THD 
       table->field[5]->store(type.ptr(), type.length(), cs);
       table->field[5]->set_notnull();
     }
-    pos=(uchar*) ((field->flags & NOT_NULL_FLAG) ?  "NO" : "YES");
+    pos=(uchar*) (!field->real_is_nullable() ?  "NO" : "YES");
     table->field[6]->store((const char*) pos,
                            strlen((const char*) pos), cs);
     store_column_type(table, field, cs, 7);

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-05-28 05:49:57 +0000
+++ b/sql/sql_table.cc	2010-06-01 13:33:14 +0000
@@ -5742,7 +5742,7 @@ compare_tables(TABLE *table,
 
     /* Check that NULL behavior is same for old and new fields */
     if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
-	(uint) (field->flags & NOT_NULL_FLAG))
+        (uint) (!field->real_is_nullable()))
     {
       *need_copy_table= ALTER_TABLE_DATA_CHANGED;
       DBUG_RETURN(0);
@@ -5807,7 +5807,7 @@ compare_tables(TABLE *table,
          table_part < table_part_end;
          table_part++)
     {
-      not_nullable= not_nullable && (! table_part->field->maybe_null());
+      not_nullable= not_nullable && (! table_part->field->is_nullable());
     }
     if ((table_key->flags & HA_NOSAME) && not_nullable)
       (*candidate_key_count)++;
@@ -6092,7 +6092,10 @@ mysql_prepare_alter_table(THD *thd, TABL
     First collect all fields from table which isn't in drop_list
   */
   Field **f_ptr,*field;
-  for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
+  Field **table_fields= table->field;
+  if (table->nullable_field)
+    table_fields= table->nullable_field;
+  for (f_ptr=table_fields ; (field= *f_ptr) ; f_ptr++)
   {
     if (field->type() == MYSQL_TYPE_STRING)
       create_info->varchar= TRUE;
@@ -7039,7 +7042,7 @@ view_err:
                key_part++)
             is_candidate_key=
               (is_candidate_key && 
-               (! table->field[key_part->fieldnr-1]->maybe_null()));
+               (! table->nullable_field[key_part->fieldnr-1]->is_nullable()));
           if (is_candidate_key)
             candidate_key_count--;
         }
@@ -7076,7 +7079,7 @@ view_err:
              key_part++)
           is_candidate_key=
             (is_candidate_key && 
-             (! table->field[key_part->fieldnr]->maybe_null()));
+             (! table->nullable_field[key_part->fieldnr]->is_nullable()));
 
         /*
            Check for "PRIMARY"
@@ -7751,7 +7754,7 @@ copy_data_between_tables(TABLE *from,TAB
   List_iterator<Create_field> it(create);
   Create_field *def;
   copy_end=copy;
-  for (Field **ptr=to->field ; *ptr ; ptr++)
+  for (Field **ptr=to->nullable_field ; *ptr ; ptr++)
   {
     def=it++;
     if (def->field)

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2010-04-28 10:04:11 +0000
+++ b/sql/sql_trigger.cc	2010-06-01 13:33:14 +0000
@@ -2024,7 +2024,7 @@ bool Table_triggers_list::process_trigge
   if (old_row_is_record1)
   {
     old_field= record1_field;
-    new_field= trigger_table->field;
+    new_field= trigger_table->nullable_field;
   }
   else
   {
@@ -2048,6 +2048,18 @@ bool Table_triggers_list::process_trigge
 
   thd->restore_sub_statement_state(&statement_state);
 
+  /*
+    Turn off temporal nullability of new fields.
+    Also check that fields to be written conform to constraints.
+   */
+  Field *field;
+  while ((field = *new_field++))
+  {
+    field->set_temporary_nullable(FALSE);
+    if (field->table == trigger_table)
+      err_status |= field->check_constraints();
+  }
+
   return err_status;
 }
 

=== modified file 'sql/sql_union.cc'
--- a/sql/sql_union.cc	2010-03-31 14:05:33 +0000
+++ b/sql/sql_union.cc	2010-06-01 13:33:14 +0000
@@ -62,6 +62,7 @@ bool select_union::send_data(List<Item> 
     return 0;
   }
   fill_record(thd, table->field, values, 1);
+  check_record(thd, table->field);
   if (thd->is_error())
     return 1;
 

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2010-05-28 05:49:57 +0000
+++ b/sql/sql_update.cc	2010-06-01 13:33:14 +0000
@@ -1833,6 +1833,8 @@ bool multi_update::send_data(List<Item> 
       fill_record(thd,
                   tmp_table->field + 1 + unupdated_check_opt_tables.elements,
                   *values_for_table[offset], 1);
+      check_record(thd,
+                   tmp_table->field + 1 + unupdated_check_opt_tables.elements);
 
       /* Write row, ignoring duplicated updates to a row */
       error= tmp_table->file->ha_write_row(tmp_table->record[0]);

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2010-04-07 12:02:19 +0000
+++ b/sql/sql_view.cc	2010-06-01 13:33:14 +0000
@@ -1867,9 +1867,9 @@ bool check_key_in_view(THD *thd, TABLE_L
         Field_translator *k;
         for (k= trans; k < end_of_trans; k++)
         {
-          Item_field *field;
-          if ((field= k->item->filed_for_view_update()) &&
-              field->field == key_part->field)
+          Item_field *field= k->item->filed_for_view_update();
+          if (field && ((field->field == table->nullable_field[key_part->fieldnr-1]) ||
+                        (field->field == table->field[key_part->fieldnr-1])))
             break;
         }
         if (k == end_of_trans)
@@ -1885,7 +1885,7 @@ bool check_key_in_view(THD *thd, TABLE_L
   {
     Field **field_ptr;
     Field_translator *fld;
-    for (field_ptr= table->field; *field_ptr; field_ptr++)
+    for (field_ptr= table->nullable_field; *field_ptr; field_ptr++)
     {
       for (fld= trans; fld < end_of_trans; fld++)
       {

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2010-05-28 05:49:57 +0000
+++ b/sql/table.cc	2010-06-01 13:33:14 +0000
@@ -1357,7 +1357,7 @@ static int open_binary_frm(THD *thd, TAB
         null_bit_pos-= 8;
       }
     }
-    if (!(reg_field->flags & NOT_NULL_FLAG))
+    if (reg_field->real_is_nullable())
     {
       if (!(null_bit_pos= (null_bit_pos + 1) & 7))
         null_pos++;
@@ -1412,7 +1412,7 @@ static int open_binary_frm(THD *thd, TAB
 	{
 	  uint fieldnr= key_part[i].fieldnr;
 	  if (!fieldnr ||
-	      share->field[fieldnr-1]->null_ptr ||
+	      share->field[fieldnr-1]->real_is_nullable() ||
 	      share->field[fieldnr-1]->key_length() !=
 	      key_part[i].length)
 	  {
@@ -1437,7 +1437,7 @@ static int open_binary_frm(THD *thd, TAB
         }
         field= key_part->field= share->field[key_part->fieldnr-1];
         key_part->type= field->key_type();
-        if (field->null_ptr)
+        if (field->real_is_nullable())
         {
           key_part->null_offset=(uint) ((uchar*) field->null_ptr -
                                         share->default_values);
@@ -1542,7 +1542,7 @@ static int open_binary_frm(THD *thd, TAB
           key_part_column = expression from the WHERE clause
           as we need to test for NULL = NULL.
         */
-        if (field->real_maybe_null())
+        if (field->real_is_nullable())
           key_part->key_part_flag|= HA_NULL_PART;
       }
       keyinfo->usable_key_parts= usable_parts; // Filesort
@@ -1700,9 +1700,9 @@ int open_table_from_share(THD *thd, TABL
                           TABLE *outparam, bool is_create_table)
 {
   int error;
-  uint records, i, bitmap_size;
+  uint records, i, bitmap_size, extra_null_bytes, extra_null_bit_pos;
   bool error_reported= FALSE;
-  uchar *record, *bitmaps;
+  uchar *record, *bitmaps, *extra_null_ptr;
   Field **field_ptr;
   DBUG_ENTER("open_table_from_share");
   DBUG_PRINT("enter",("name: '%s.%s'  form: 0x%lx", share->db.str,
@@ -1746,10 +1746,16 @@ int open_table_from_share(THD *thd, TABL
   if (prgflag & (READ_ALL+EXTRA_RECORD))
     records++;
 
-  if (!(record= (uchar*) alloc_root(&outparam->mem_root,
-                                   share->rec_buff_length * records)))
+  // Extra bytes to temporarily store null_bits for NOT NULL fields
+  extra_null_bytes= 0;
+  if (records)
+    extra_null_bytes= (share->fields - share->null_fields + 7) / 8;
+  if (!(record= (uchar*) alloc_root(&outparam->mem_root, extra_null_bytes +
+                                    share->rec_buff_length * records)))
     goto err;                                   /* purecov: inspected */
 
+  if (records)
+    bzero((char*)(record + (share->rec_buff_length * records)),extra_null_bytes);
   if (records == 0)
   {
     /* We are probably in hard repair, and the buffers should not be used */
@@ -1780,11 +1786,14 @@ int open_table_from_share(THD *thd, TABL
 #endif
 
   if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root,
-                                          (uint) ((share->fields+1)*
+                                          (uint) ((2*(share->fields+1))*
                                                   sizeof(Field*)))))
     goto err;                                   /* purecov: inspected */
 
+  /* normal Fields */
   outparam->field= field_ptr;
+  extra_null_ptr= outparam->record[0] + (share->rec_buff_length * records);
+  extra_null_bit_pos= 0;
 
   record= (uchar*) outparam->record[0]-1;	/* Fieldstart = 1 */
   if (share->null_field_first)
@@ -1798,14 +1807,48 @@ int open_table_from_share(THD *thd, TABL
   {
     if (!((*field_ptr)= share->field[i]->clone(&outparam->mem_root, outparam)))
       goto err;
+    if (!((*field_ptr)->real_is_nullable()))
+    {
+      (*field_ptr)->null_ptr= extra_null_ptr;
+      (*field_ptr)->null_bit= ((uchar) 1) << extra_null_bit_pos;
+      if (++extra_null_bit_pos == 8)
+      {
+        extra_null_bit_pos= 0;
+        extra_null_ptr++;
+      }
+    }
+  }
+  (*field_ptr)= 0;                              // End marker
+
+  /* nullable Fields */
+  outparam->nullable_field= ++field_ptr;
+  extra_null_ptr= outparam->record[0] + (share->rec_buff_length * records);
+  extra_null_bit_pos= 0;
+
+  /* Setup copy of fields from share, but use the right alias and record */
+  for (i=0 ; i < share->fields; i++, field_ptr++)
+  {
+    if (!((*field_ptr)= share->field[i]->clone(&outparam->mem_root, outparam)))
+      goto err;
+    if (!((*field_ptr)->real_is_nullable()))
+    {
+      (*field_ptr)->null_ptr= extra_null_ptr;
+      (*field_ptr)->null_bit= ((uchar) 1) << extra_null_bit_pos;
+      if (++extra_null_bit_pos == 8)
+      {
+        extra_null_bit_pos= 0;
+        extra_null_ptr++;
+      }
+    }
   }
   (*field_ptr)= 0;                              // End marker
 
   if (share->found_next_number_field)
     outparam->found_next_number_field=
-      outparam->field[(uint) (share->found_next_number_field - share->field)];
+      outparam->nullable_field[(uint) (share->found_next_number_field - share->field)];
   if (share->timestamp_field)
-    outparam->timestamp_field= (Field_timestamp*) outparam->field[share->timestamp_field_offset];
+    outparam->timestamp_field=
+      (Field_timestamp*) outparam->nullable_field[share->timestamp_field_offset];
 
 
   /* Fix key->name and key_part->field */
@@ -2036,6 +2079,12 @@ int closefrm(register TABLE *table, bool
       delete *ptr;
     table->field= 0;
   }
+  if (table->nullable_field)
+  {
+    for (Field **ptr=table->nullable_field ; *ptr ; ptr++)
+      delete *ptr;
+    table->nullable_field= 0;
+  }
   delete table->file;
   table->file= 0;				/* For easier errorchecking */
 #ifdef WITH_PARTITION_STORAGE_ENGINE

=== modified file 'sql/table.h'
--- a/sql/table.h	2010-05-28 05:49:57 +0000
+++ b/sql/table.h	2010-06-01 13:33:14 +0000
@@ -882,7 +882,9 @@ private:
 public:
 
   THD	*in_use;                        /* Which thread uses this */
-  Field **field;			/* Pointer to fields */
+  Field **field;			/* Pointer to normal fields */
+  Field **nullable_field;       	/* Pointer to nullable copy of fields
+                                           used during trigger processing */
 
   uchar *record[2];			/* Pointer to records */
   uchar *write_row_record;		/* Used as optimisation in

=== modified file 'sql/unireg.cc'
--- a/sql/unireg.cc	2010-03-31 14:05:33 +0000
+++ b/sql/unireg.cc	2010-06-01 13:33:14 +0000
@@ -1043,7 +1043,7 @@ static bool make_empty_rec(THD *thd, Fil
 
     if (!(field->flags & NOT_NULL_FLAG))
     {
-      *regfield->null_ptr|= regfield->null_bit;
+      regfield->set_null();
       null_count++;
     }
 

=== modified file 'storage/csv/ha_tina.cc'
--- a/storage/csv/ha_tina.cc	2010-04-01 12:19:08 +0000
+++ b/storage/csv/ha_tina.cc	2010-06-01 13:33:14 +0000
@@ -1672,7 +1672,7 @@ int ha_tina::create(const char *name, TA
   */
   for (Field **field= table_arg->s->field; *field; field++)
   {
-    if ((*field)->real_maybe_null())
+    if ((*field)->real_is_nullable())
     {
       my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "nullable columns");
       DBUG_RETURN(HA_ERR_UNSUPPORTED);

=== modified file 'storage/federated/ha_federated.cc'
--- a/storage/federated/ha_federated.cc	2010-03-31 14:05:33 +0000
+++ b/storage/federated/ha_federated.cc	2010-06-01 13:33:14 +0000
@@ -1717,7 +1717,7 @@ static inline uint field_in_record_is_nu
   int null_offset;
   DBUG_ENTER("ha_federated::field_in_record_is_null");
 
-  if (!field->null_ptr)
+  if (!field->real_is_nullable())
     DBUG_RETURN(0);
 
   null_offset= (uint) ((char*)field->null_ptr - (char*)table->record[0]);

=== modified file 'storage/heap/ha_heap.cc'
--- a/storage/heap/ha_heap.cc	2010-03-31 14:05:33 +0000
+++ b/storage/heap/ha_heap.cc	2010-06-01 13:33:14 +0000
@@ -691,7 +691,7 @@ int ha_heap::create(const char *name, TA
         seg->charset= &my_charset_bin;
       else
         seg->charset= field->charset_for_protocol();
-      if (field->null_ptr)
+      if (field->real_is_nullable())
       {
 	seg->null_bit= field->null_bit;
 	seg->null_pos= (uint) (field->null_ptr - (uchar*) table_arg->record[0]);

=== modified file 'storage/ibmdb2i/ha_ibmdb2i.cc'
--- a/storage/ibmdb2i/ha_ibmdb2i.cc	2009-12-22 06:36:04 +0000
+++ b/storage/ibmdb2i/ha_ibmdb2i.cc	2010-06-01 13:33:14 +0000
@@ -2377,7 +2377,7 @@ int ha_ibmdb2i::add_index(TABLE *table_a
         for (int j=0 ; j < key_info[i].key_parts ;j++)
         {
           uint fieldnr= key_info[i].key_part[j].fieldnr;
-          if (table_arg->s->field[fieldnr]->null_ptr ||
+          if (table_arg->s->field[fieldnr]->real_is_nullable() ||
               table_arg->s->field[fieldnr]->key_length() !=
               key_info[i].key_part[j].length)
           {

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	2010-05-26 01:44:33 +0000
+++ b/storage/innobase/handler/ha_innodb.cc	2010-06-01 13:33:14 +0000
@@ -3927,7 +3927,7 @@ field_in_record_is_null(
 {
 	int	null_offset;
 
-	if (!field->null_ptr) {
+	if (!field->real_is_nullable()) {
 
 		return(0);
 	}
@@ -4612,7 +4612,7 @@ include_field:
 			prebuilt->need_to_access_clustered = TRUE;
 		}
 
-		if (field->null_ptr) {
+		if (field->real_is_nullable()) {
 			templ->mysql_null_byte_offset =
 				(ulint) ((char*) field->null_ptr
 					- (char*) table->record[0]);
@@ -5121,7 +5121,7 @@ calc_row_difference(
 			;
 		}
 
-		if (field->null_ptr) {
+		if (field->real_is_nullable()) {
 			if (field_in_record_is_null(table, field,
 							(char*) old_row)) {
 				o_len = UNIV_SQL_NULL;
@@ -6191,7 +6191,7 @@ create_table_def(
 
 		col_type = get_innobase_type_from_mysql_type(&unsigned_type,
 									field);
-		if (field->null_ptr) {
+		if (field->real_is_nullable()) {
 			nulls_allowed = 0;
 		} else {
 			nulls_allowed = DATA_NOT_NULL;

=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc	2010-04-19 12:09:44 +0000
+++ b/storage/myisam/ha_myisam.cc	2010-06-01 13:33:14 +0000
@@ -279,7 +279,7 @@ int table2myisam(TABLE *table_arg, MI_KE
       keydef[i].seg[j].bit_pos= 0;
       keydef[i].seg[j].language= field->charset_for_protocol()->number;
 
-      if (field->null_ptr)
+      if (field->real_is_nullable())
       {
         keydef[i].seg[j].null_bit= field->null_bit;
         keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
@@ -363,7 +363,7 @@ int table2myisam(TABLE *table_arg, MI_KE
                                   found->type() == MYSQL_TYPE_VAR_STRING ?
                                   FIELD_SKIP_ENDSPACE :
                                   FIELD_SKIP_PRESPACE);
-    if (found->null_ptr)
+    if (found->real_is_nullable())
     {
       recinfo_pos->null_bit= found->null_bit;
       recinfo_pos->null_pos= (uint) (found->null_ptr -


Attachment: [text/bzr-bundle] bzr/jon.hauglid@sun.com-20100601133314-ycb0c808cmnp0x6w.bundle
Thread
bzr commit into mysql-next-mr-bugfixing branch (jon.hauglid:3221) Bug#6295Jon Olav Hauglid1 Jun