Commit 7b511544 authored by unknown's avatar unknown
Browse files

Support for TIMESTAMP columns holding NULL values. Unlike all other

column types TIMESTAMP is NOT NULL by default, so in order to have 
TIMESTAMP column holding NULL valaues you have to specify NULL as
one of its attributes (this needed for backward compatibility).

Main changes:
Replaced TABLE::timestamp_default_now/on_update_now members with
TABLE::timestamp_auto_set_type flag which is used everywhere
for determining if we should auto-set value of TIMESTAMP field 
during this operation or not. We are also use Field_timestamp::set_time()
instead of handler::update_timestamp() in handlers.


mysql-test/r/type_timestamp.result:
  Added test for TIMESTAMP columns which are able to store NULL values.
mysql-test/t/type_timestamp.test:
  Added test for TIMESTAMP columns which are able to store NULL values.
sql/field.cc:
  Added support for TIMESTAMP fields holding NULL values.
  We don't need Field_timestamp::set_timestamp_offsets() anymore.
  Instead we need Field_timestamp::get_auto_set_type() function
  which will convert TIMESTAMP auto-set type stored in Field in 
  unireg_check to value from timestamp_auto_set_type_enum.
  (We can't replace this function with additional Field_timestamp member
  and some code in constructor because then we will have troubles
  with Field::new_field() method).
  We should also set field to not null in Field_timestamp::set_time() now.
sql/field.h:
  Added support for TIMESTAMP fields holding NULL values.
  We don't need Field_timestamp::set_timestamp_offsets() anymore.
  Instead we need Field_timestamp::get_auto_set_type() function,
  which will convert TIMESTAMP auto-set type stored in Field in 
  unireg_check to value from timestamp_auto_set_type_enum.
  We also have to support NULL values in Field_timestamp::get_timestamp()
  function.
sql/field_conv.cc:
  Added comment clarifying behavior in case of TIMESTAMP fields which are
  able to store NULL values.
sql/ha_berkeley.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/ha_heap.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/ha_innodb.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/ha_isam.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/ha_isammrg.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/ha_myisam.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/ha_myisammrg.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/ha_ndbcluster.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now for determining 
  if we should auto-set value of TIMESTAMP field during this operation.
  We are also use Field_timestamp::set_time() instead of 
  handler::update_timestamp().
sql/handler.cc:
  handler::update_timestamp() is no longer needed since now we use
  Field_timestamp::set_time() instead.
  (we can't use handler::update_timestamp() anyway since field position
  only is not enough for TIMESTAMP fields which are able to store NULLs)
sql/handler.h:
  handler::update_timestamp() is no longer needed since now we use
  Field_timestamp::set_time() instead.
sql/item_timefunc.cc:
  Since now TIMESTAMP fields can hold NULL values we should take this into
  account.
sql/sql_base.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now. 
  (Here we use Field_timestamp::get_auto_set_type() to setup its value
   before further statement execution).
sql/sql_insert.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now.
sql/sql_load.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now.
sql/sql_parse.cc:
  Added support for TIMESTAMP fields holding NULL values.
  We should distinguish NULL default values and non-specified default
  values for such fields (because latter could mean DEFAULT NOW()
  ON UPDATE NOW() in some cases).
sql/sql_show.cc:
  Added support for TIMESTAMP fields holding NULL values.
  Unlike all other fields these are NOT NULL by default
  so we have to specify NULL attribute explicitly for them.
sql/sql_table.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now.
sql/sql_update.cc:
  Now we use TABLE::timestamp_field_type instead of 
  TABLE::timestamp_default_now/on_update_now.
sql/sql_yacc.yy:
  Added support for TIMESTAMP fields holding NULL values.
  Unlike all other fields these are NOT NULL by default
  (so we have to set NOT_NULL_FLAG properly for them).
sql/table.h:
  Added timestamp_auto_set_type enum which values are used for indicating
  during which operations we should automatically set TIMESTAPM field
  value to current timestamp.
  TABLE: Replaced timestamp_default_now/on_update_now members with
  timestamp_auto_set_type flag (Now when TIMESTAMP field are able to 
  store NULL values, single position of field in record is not enough 
  for updating this field anyway).
parent 9ff04fe5
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -365,6 +365,35 @@ select * from t1;
t1	i
2004-04-01 00:00:00	10
drop table t1;
create table t1 (a timestamp null, b timestamp null);
show create table t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `a` timestamp NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  `b` timestamp NULL default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 values (NULL, NULL);
SET TIMESTAMP=1000000017;
insert into t1 values ();
select * from t1;
a	b
NULL	NULL
2001-09-09 04:46:57	NULL
drop table t1;
create table t1 (a timestamp null default null, b timestamp null default '2003-01-01 00:00:00');
show create table t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `a` timestamp NULL default NULL,
  `b` timestamp NULL default '2003-01-01 00:00:00'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 values (NULL, NULL);
insert into t1 values (DEFAULT, DEFAULT);
select * from t1;
a	b
NULL	NULL
NULL	2003-01-01 00:00:00
drop table t1;
create table t1 (ts timestamp(19));
show create table t1;
Table	Create Table
+20 −0
Original line number Diff line number Diff line
@@ -234,7 +234,27 @@ alter table t1 add i int default 10;
select * from t1;
drop table t1;

#
# Test for TIMESTAMP columns which are able to store NULLs
# (Auto-set property should work for them and NULL values
#  should be OK as default values)
#
create table t1 (a timestamp null, b timestamp null);
show create table t1;
insert into t1 values (NULL, NULL);
SET TIMESTAMP=1000000017;
insert into t1 values ();
select * from t1;
drop table t1;

create table t1 (a timestamp null default null, b timestamp null default '2003-01-01 00:00:00');
show create table t1;
insert into t1 values (NULL, NULL);
insert into t1 values (DEFAULT, DEFAULT);
select * from t1;
drop table t1;

#
# Test for bug #4491, TIMESTAMP(19) should be possible to create and not
# only read in 4.0
#
+30 −17
Original line number Diff line number Diff line
@@ -2902,11 +2902,12 @@ void Field_double::sql_type(String &res) const
 */

Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
                                 uchar *null_ptr_arg, uchar null_bit_arg,
				 enum utype unireg_check_arg,
				 const char *field_name_arg,
				 struct st_table *table_arg,
				 CHARSET_INFO *cs)
  :Field_str(ptr_arg, 19, (uchar*) 0,0,
  :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
	     unireg_check_arg, field_name_arg, table_arg, cs)
{
  /* For 4.0 MYD and 4.0 InnoDB compatibility */
@@ -2922,23 +2923,33 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,


/*
    Sets TABLE::timestamp_default_now and TABLE::timestamp_on_update_now 
    members according to unireg type of this TIMESTAMP field.
  Get auto-set type for TIMESTAMP field.

  SYNOPSIS
    Field_timestamp::set_timestamp_offsets()
    get_auto_set_type()

  DESCRIPTION
    Returns value indicating during which operations this TIMESTAMP field
    should be auto-set to current timestamp.
*/
void Field_timestamp::set_timestamp_offsets()
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
{
  ulong timestamp= (ulong) (ptr - (char*) table->record[0]) + 1;
  
  DBUG_ASSERT(table->timestamp_field == this && unireg_check != NONE);

  table->timestamp_default_now= 
    (unireg_check == TIMESTAMP_UN_FIELD)? 0 : timestamp;
  table->timestamp_on_update_now= 
    (unireg_check == TIMESTAMP_DN_FIELD)? 0 : timestamp;
  switch (unireg_check)
  {
  case TIMESTAMP_DN_FIELD:
    return TIMESTAMP_AUTO_SET_ON_INSERT;
  case TIMESTAMP_UN_FIELD:
    return TIMESTAMP_AUTO_SET_ON_UPDATE;
  case TIMESTAMP_DNUN_FIELD:
    return TIMESTAMP_AUTO_SET_ON_BOTH;
  default:
    /*
      Normally this function should not be called for TIMESTAMPs without
      auto-set property.
    */
    DBUG_ASSERT(0);
    return TIMESTAMP_NO_AUTO_SET;
  }
}


@@ -3237,6 +3248,7 @@ void Field_timestamp::sql_type(String &res) const
void Field_timestamp::set_time()
{
  long tmp= (long) table->in_use->query_start();
  set_notnull();
#ifdef WORDS_BIGENDIAN
  if (table->db_low_byte_first)
  {
@@ -5917,8 +5929,9 @@ Field *make_field(char *ptr, uint32 field_length,
			      f_is_zerofill(pack_flag) != 0,
			      f_is_dec(pack_flag) == 0);
  case FIELD_TYPE_TIMESTAMP:
    return new Field_timestamp(ptr,field_length,
			       unireg_check, field_name, table, field_charset);
    return new Field_timestamp(ptr,field_length, null_pos, null_bit,
                               unireg_check, field_name, table,
                               field_charset);
  case FIELD_TYPE_YEAR:
    return new Field_year(ptr,field_length,null_pos,null_bit,
			  unireg_check, field_name, table);
+6 −2
Original line number Diff line number Diff line
@@ -676,6 +676,7 @@ class Field_null :public Field_str {
class Field_timestamp :public Field_str {
public:
  Field_timestamp(char *ptr_arg, uint32 len_arg,
                  uchar *null_ptr_arg, uchar null_bit_arg,
		  enum utype unireg_check_arg, const char *field_name_arg,
		  struct st_table *table_arg,
		  CHARSET_INFO *cs);
@@ -705,8 +706,11 @@ class Field_timestamp :public Field_str {
    else
      Field::set_default();
  }
  inline long get_timestamp()
  /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
  inline long get_timestamp(my_bool *null_value)
  {
    if ((*null_value= is_null()))
      return 0;
#ifdef WORDS_BIGENDIAN
    if (table->db_low_byte_first)
      return sint4korr(ptr);
@@ -718,7 +722,7 @@ class Field_timestamp :public Field_str {
  bool get_date(TIME *ltime,uint fuzzydate);
  bool get_time(TIME *ltime);
  field_cast_enum field_cast_type() { return FIELD_CAST_TIMESTAMP; }
  void set_timestamp_offsets();
  timestamp_auto_set_type get_auto_set_type() const;
};


+2 −1
Original line number Diff line number Diff line
@@ -164,7 +164,8 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions)

  /*
    Check if this is a special type, which will get a special walue
    when set to NULL
    when set to NULL (TIMESTAMP fields which allow setting to NULL
    are handled by first check).
  */
  if (field->type() == FIELD_TYPE_TIMESTAMP)
  {
Loading