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:
@@ -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
|
||||
|
@@ -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
|
||||
#
|
||||
|
43
sql/field.cc
43
sql/field.cc
@@ -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);
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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) &&
|
||||
|
@@ -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.
|
||||
|
@@ -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);
|
||||
|
@@ -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(<ime, 0))
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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 ||
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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; }
|
||||
|
29
sql/table.h
29
sql/table.h
@@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user