1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

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.
This commit is contained in:
dlenev@brandersnatch.localdomain
2004-10-01 18:54:06 +04:00
parent d03f447f84
commit 2511990c97
25 changed files with 195 additions and 111 deletions

View File

@@ -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

View File

@@ -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
#

View File

@@ -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);

View File

@@ -676,6 +676,7 @@ public:
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 @@ public:
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 @@ public:
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;
};

View File

@@ -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)
{

View File

@@ -856,8 +856,8 @@ int ha_berkeley::write_row(byte * record)
DBUG_ENTER("write_row");
statistic_increment(ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(record+table->timestamp_default_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
if (table->next_number_field && record == table->record[0])
update_auto_increment();
if ((error=pack_row(&row, record,1)))
@@ -1103,8 +1103,8 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
LINT_INIT(error);
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_row+table->timestamp_on_update_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
if (hidden_primary_key)
{

View File

@@ -87,8 +87,8 @@ void ha_heap::set_keys_for_scanning(void)
int ha_heap::write_row(byte * buf)
{
statistic_increment(ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0])
update_auto_increment();
return heap_write(file,buf);
@@ -97,8 +97,8 @@ int ha_heap::write_row(byte * buf)
int ha_heap::update_row(const byte * old_data, byte * new_data)
{
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return heap_update(file,old_data,new_data);
}

View File

@@ -2218,8 +2218,8 @@ ha_innobase::write_row(
statistic_increment(ha_write_count, &LOCK_status);
if (table->timestamp_default_now)
update_timestamp(record + table->timestamp_default_now - 1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@@ -2590,8 +2590,8 @@ ha_innobase::update_row(
ut_ad(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
if (table->timestamp_on_update_now)
update_timestamp(new_row + table->timestamp_on_update_now - 1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;

View File

@@ -70,8 +70,8 @@ uint ha_isam::min_record_length(uint options) const
int ha_isam::write_row(byte * buf)
{
statistic_increment(ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0])
update_auto_increment();
return !nisam_write(file,buf) ? 0 : my_errno ? my_errno : -1;
@@ -80,8 +80,8 @@ int ha_isam::write_row(byte * buf)
int ha_isam::update_row(const byte * old_data, byte * new_data)
{
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return !nisam_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
}

View File

@@ -78,8 +78,8 @@ int ha_isammrg::write_row(byte * buf)
int ha_isammrg::update_row(const byte * old_data, byte * new_data)
{
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return !mrg_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
}

View File

@@ -251,8 +251,8 @@ int ha_myisam::write_row(byte * buf)
statistic_increment(ha_write_count,&LOCK_status);
/* If we have a timestamp column, update it to the current time */
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
/*
If we have an auto_increment column and we are writing a changed row
@@ -1070,8 +1070,8 @@ bool ha_myisam::is_crashed() const
int ha_myisam::update_row(const byte * old_data, byte * new_data)
{
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return mi_update(file,old_data,new_data);
}

View File

@@ -82,8 +82,8 @@ int ha_myisammrg::close(void)
int ha_myisammrg::write_row(byte * buf)
{
statistic_increment(ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
if (table->next_number_field && buf == table->record[0])
update_auto_increment();
return myrg_write(file,buf);
@@ -92,8 +92,8 @@ int ha_myisammrg::write_row(byte * buf)
int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
{
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
return myrg_update(file,old_data,new_data);
}

View File

@@ -1533,8 +1533,8 @@ int ha_ndbcluster::write_row(byte *record)
}
statistic_increment(ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(record+table->timestamp_default_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time();
has_auto_increment= (table->next_number_field && record == table->record[0]);
if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)))
@@ -1683,8 +1683,8 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
DBUG_ENTER("update_row");
statistic_increment(ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
table->timestamp_field->set_time();
/* Check for update of primary key for special handling */
if ((table->primary_key != MAX_KEY) &&

View File

@@ -942,22 +942,6 @@ int handler::read_first_row(byte * buf, uint primary_key)
}
/* Set a timestamp in record */
void handler::update_timestamp(byte *record)
{
long skr= (long) current_thd->query_start();
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
int4store(record,skr);
}
else
#endif
longstore(record,skr);
return;
}
/*
Updates field with field_type NEXT_NUMBER according to following:
if field = 0 change field to the next free key in database.

View File

@@ -287,7 +287,6 @@ public:
{}
virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
int ha_open(const char *name, int mode, int test_if_locked);
void update_timestamp(byte *record);
void update_auto_increment();
virtual void print_error(int error, myf errflag);
virtual bool get_error_message(int error, String *buf);

View File

@@ -989,7 +989,7 @@ longlong Item_func_unix_timestamp::val_int()
{ // Optimize timestamp field
Field *field=((Item_field*) args[0])->field;
if (field->type() == FIELD_TYPE_TIMESTAMP)
return ((Field_timestamp*) field)->get_timestamp();
return ((Field_timestamp*) field)->get_timestamp(&null_value);
}
if (get_arg0_date(&ltime, 0))

View File

@@ -945,7 +945,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
table->keys_in_use_for_query= table->keys_in_use;
table->used_keys= table->keys_for_keyread;
if (table->timestamp_field)
table->timestamp_field->set_timestamp_offsets();
table->timestamp_field_type= table->timestamp_field->get_auto_set_type();
DBUG_ASSERT(table->key_read == 0);
DBUG_RETURN(table);
}

View File

@@ -45,8 +45,8 @@ static void unlink_blobs(register TABLE *table);
/*
Check if insert fields are correct.
Sets table->timestamp_default_now/on_update_now to 0 o leaves it to point
to timestamp field, depending on if timestamp should be updated or not.
Sets table->timestamp_field_type to TIMESTAMP_NO_AUTO_SET or leaves it
as is, depending on if timestamp should be updated or not.
*/
int
@@ -67,7 +67,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
check_grant_all_columns(thd,INSERT_ACL,table))
return -1;
#endif
table->timestamp_default_now= table->timestamp_on_update_now= 0;
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
}
else
{ // Part field list
@@ -97,7 +97,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
}
if (table->timestamp_field && // Don't set timestamp if used
table->timestamp_field->query_id == thd->query_id)
table->timestamp_default_now= table->timestamp_on_update_now= 0;
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
}
// For the values we need select_priv
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -569,7 +569,8 @@ int write_record(TABLE *table,COPY_INFO *info)
*/
if (last_uniq_key(table,key_nr) &&
!table->file->referenced_by_foreign_key() &&
table->timestamp_default_now == table->timestamp_on_update_now)
(table->timestamp_field_type == TIMESTAMP_NO_AUTO_SET ||
table->timestamp_field_type == TIMESTAMP_AUTO_SET_ON_BOTH))
{
if ((error=table->file->update_row(table->record[1],
table->record[0])))
@@ -645,8 +646,7 @@ public:
bool query_start_used,last_insert_id_used,insert_id_used;
int log_query;
ulonglong last_insert_id;
ulong timestamp_default_now;
ulong timestamp_on_update_now;
timestamp_auto_set_type timestamp_field_type;
uint query_length;
delayed_row(enum_duplicates dup_arg, int log_query_arg)
@@ -940,7 +940,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
copy->timestamp_field=
(Field_timestamp*) copy->field[table->timestamp_field_offset];
copy->timestamp_field->unireg_check= table->timestamp_field->unireg_check;
copy->timestamp_field->set_timestamp_offsets();
copy->timestamp_field_type= copy->timestamp_field->get_auto_set_type();
}
/* _rowid is not used with delayed insert */
@@ -995,8 +995,7 @@ static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic,
row->last_insert_id_used= thd->last_insert_id_used;
row->insert_id_used= thd->insert_id_used;
row->last_insert_id= thd->last_insert_id;
row->timestamp_default_now= table->timestamp_default_now;
row->timestamp_on_update_now= table->timestamp_on_update_now;
row->timestamp_field_type= table->timestamp_field_type;
di->rows.push_back(row);
di->stacked_inserts++;
@@ -1335,8 +1334,7 @@ bool delayed_insert::handle_inserts(void)
thd.last_insert_id=row->last_insert_id;
thd.last_insert_id_used=row->last_insert_id_used;
thd.insert_id_used=row->insert_id_used;
table->timestamp_default_now= row->timestamp_default_now;
table->timestamp_on_update_now= row->timestamp_on_update_now;
table->timestamp_field_type= row->timestamp_field_type;
info.handle_duplicates= row->dup;
if (info.handle_duplicates == DUP_IGNORE ||
@@ -1631,7 +1629,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
field=table->field+table->fields - values.elements;
/* Don't set timestamp if used */
table->timestamp_default_now= table->timestamp_on_update_now= 0;
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
table->next_number_field=table->found_next_number_field;

View File

@@ -264,7 +264,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (!(error=test(read_info.error)))
{
if (use_timestamp)
table->timestamp_default_now= table->timestamp_on_update_now= 0;
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
table->next_number_field=table->found_next_number_field;
if (handle_duplicates == DUP_IGNORE ||

View File

@@ -4142,7 +4142,12 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
}
else if (default_value->type() == Item::NULL_ITEM)
{
default_value=0;
/*
TIMESTAMP type should be able to distingush non-specified default
value and default value NULL later.
*/
if (type != FIELD_TYPE_TIMESTAMP)
default_value= 0;
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
NOT_NULL_FLAG)
{
@@ -4334,7 +4339,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->length=((new_field->length+1)/2)*2; /* purecov: inspected */
new_field->length= min(new_field->length,14); /* purecov: inspected */
}
new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG | NOT_NULL_FLAG;
new_field->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
if (default_value)
{
/* Grammar allows only NOW() value for ON UPDATE clause */
@@ -4352,6 +4357,9 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
else
new_field->unireg_check= (on_update_value?Field::TIMESTAMP_UN_FIELD:
Field::NONE);
if (default_value->type() == Item::NULL_ITEM)
new_field->def= 0;
}
else
{

View File

@@ -710,10 +710,11 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
protocol->store(field->has_charset() ? field->charset()->name : "NULL",
system_charset_info);
/*
Altough TIMESTAMP fields can't contain NULL as its value they
Even if TIMESTAMP field can't contain NULL as its value it
will accept NULL if you will try to insert such value and will
convert it to current TIMESTAMP. So YES here means that NULL
is allowed for assignment but can't be returned.
convert NULL value to current TIMESTAMP. So YES here means
that NULL is allowed for assignment (but may be won't be
returned).
*/
pos=(byte*) ((flags & NOT_NULL_FLAG) &&
field->type() != FIELD_TYPE_TIMESTAMP ?
@@ -1291,7 +1292,14 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (flags & NOT_NULL_FLAG)
packet->append(" NOT NULL", 9);
else if (field->type() == FIELD_TYPE_TIMESTAMP)
{
/*
TIMESTAMP field require explicit NULL flag, because unlike
all other fields they are treated as NOT NULL by default.
*/
packet->append(" NULL", 5);
}
/*
Again we are using CURRENT_TIMESTAMP instead of NOW because it is

View File

@@ -3053,12 +3053,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
/*
We don't want update TIMESTAMP fields during ALTER TABLE
and copy_data_between_tables uses only write_row() for new_table so
don't need to set up timestamp_on_update_now member.
*/
new_table->timestamp_default_now= 0;
/* We don't want update TIMESTAMP fields during ALTER TABLE. */
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
new_table->next_number_field=new_table->found_next_number_field;
thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
thd->cuted_fields=0L;

View File

@@ -116,7 +116,7 @@ int mysql_update(THD *thd,
{
// Don't set timestamp column if this is modified
if (table->timestamp_field->query_id == thd->query_id)
table->timestamp_on_update_now= 0;
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
else
table->timestamp_field->query_id=timestamp_query_id;
}
@@ -526,7 +526,7 @@ int mysql_multi_update(THD *thd,
// Only set timestamp column if this is not modified
if (table->timestamp_field &&
table->timestamp_field->query_id == thd->query_id)
table->timestamp_on_update_now= 0;
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
/* if table will be updated then check that it is unique */
if (table->map & item_tables)

View File

@@ -1415,10 +1415,21 @@ type:
if (YYTHD->variables.sql_mode & MODE_MAXDB)
$$=FIELD_TYPE_DATETIME;
else
{
/*
Unlike other types TIMESTAMP fields are NOT NULL by default.
*/
Lex->type|= NOT_NULL_FLAG;
$$=FIELD_TYPE_TIMESTAMP;
}
}
| TIMESTAMP '(' NUM ')' { Lex->length=$3.str;
$$=FIELD_TYPE_TIMESTAMP; }
| TIMESTAMP '(' NUM ')'
{
LEX *lex= Lex;
lex->length= $3.str;
lex->type|= NOT_NULL_FLAG;
$$= FIELD_TYPE_TIMESTAMP;
}
| DATETIME { $$=FIELD_TYPE_DATETIME; }
| TINYBLOB { Lex->charset=&my_charset_bin;
$$=FIELD_TYPE_TINY_BLOB; }

View File

@@ -57,6 +57,16 @@ typedef struct st_filesort_info
} FILESORT_INFO;
/*
Values in this enum are used to indicate during which operations value
of TIMESTAMP field should be set to current timestamp.
*/
enum timestamp_auto_set_type
{
TIMESTAMP_NO_AUTO_SET= 0, TIMESTAMP_AUTO_SET_ON_INSERT= 1,
TIMESTAMP_AUTO_SET_ON_UPDATE= 2, TIMESTAMP_AUTO_SET_ON_BOTH= 3
};
/* Table cache entry struct */
class Field_timestamp;
@@ -100,15 +110,18 @@ struct st_table {
uint system; /* Set if system record */
/*
These two members hold offset in record + 1 for TIMESTAMP field
with NOW() as default value or/and with ON UPDATE NOW() option.
If 0 then such field is absent in this table or auto-set for default
or/and on update should be temporaly disabled for some reason.
These values is setup to offset value for each statement in open_table()
and turned off in statement processing code (see mysql_update as example).
If this table has TIMESTAMP field with auto-set property (pointed by
timestamp_field member) then this variable indicates during which
operations (insert only/on update/in both cases) we should set this
field to current timestamp. If there are no such field in this table
or we should not automatically set its value during execution of current
statement then the variable contains TIMESTAMP_NO_AUTO_SET (i.e. 0).
Value of this variable is set for each statement in open_table() and
if needed cleared later in statement processing code (see mysql_update()
as example).
*/
ulong timestamp_default_now;
ulong timestamp_on_update_now;
timestamp_auto_set_type timestamp_field_type;
/* Index of auto-updated TIMESTAMP field in field array */
uint timestamp_field_offset;