mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
Merge dellis@bk-internal.mysql.com:/home/bk/mysql-4.1
into goetia.(none):/home/dellis/mysqlab/bk/mysql-4.1
This commit is contained in:
commit
61ef4d2923
32 changed files with 390 additions and 189 deletions
|
@ -12,6 +12,27 @@ Created 1/16/1996 Heikki Tuuri
|
|||
#include "data0type.ic"
|
||||
#endif
|
||||
|
||||
/**********************************************************************
|
||||
This function is used to find the storage length in bytes of the first n
|
||||
characters for prefix indexes using a multibyte character set. The function
|
||||
finds charset information and returns length of prefix_len characters in the
|
||||
index field in bytes.
|
||||
|
||||
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
|
||||
this function, you MUST change also the prototype here! */
|
||||
|
||||
ulint
|
||||
innobase_get_at_most_n_mbchars(
|
||||
/*===========================*/
|
||||
/* out: number of bytes occupied by the first
|
||||
n characters */
|
||||
ulint charset_id, /* in: character set id */
|
||||
ulint prefix_len, /* in: prefix length in bytes of the index
|
||||
(this has to be divided by mbmaxlen to get the
|
||||
number of CHARACTERS n in the prefix) */
|
||||
ulint data_len, /* in: length of the string in bytes */
|
||||
const char* str); /* in: character string */
|
||||
|
||||
/* At the database startup we store the default-charset collation number of
|
||||
this MySQL installation to this global variable. If we have < 4.1.2 format
|
||||
column definitions, or records in the insert buffer, we use this
|
||||
|
@ -23,6 +44,63 @@ ulint data_mysql_latin1_swedish_charset_coll = 99999999;
|
|||
dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0};
|
||||
dtype_t* dtype_binary = &dtype_binary_val;
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a string type has to be compared by the MySQL comparison functions.
|
||||
InnoDB internally only handles binary byte string comparisons, as well as
|
||||
latin1_swedish_ci strings. For example, UTF-8 strings have to be compared
|
||||
by MySQL. */
|
||||
|
||||
ibool
|
||||
dtype_str_needs_mysql_cmp(
|
||||
/*======================*/
|
||||
/* out: TRUE if a string type that requires
|
||||
comparison with MySQL functions */
|
||||
dtype_t* dtype) /* in: type struct */
|
||||
{
|
||||
if (dtype->mtype == DATA_MYSQL
|
||||
|| dtype->mtype == DATA_VARMYSQL
|
||||
|| (dtype->mtype == DATA_BLOB
|
||||
&& 0 == (dtype->prtype & DATA_BINARY_TYPE)
|
||||
&& dtype_get_charset_coll(dtype->prtype) !=
|
||||
data_mysql_latin1_swedish_charset_coll)) {
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
For the documentation of this function, see innobase_get_at_most_n_mbchars()
|
||||
in ha_innodb.cc. */
|
||||
|
||||
ulint
|
||||
dtype_get_at_most_n_mbchars(
|
||||
/*========================*/
|
||||
dtype_t* dtype,
|
||||
ulint prefix_len,
|
||||
ulint data_len,
|
||||
const char* str)
|
||||
{
|
||||
ut_a(data_len != UNIV_SQL_NULL);
|
||||
|
||||
if (dtype_str_needs_mysql_cmp(dtype)) {
|
||||
return(innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(dtype->prtype),
|
||||
prefix_len, data_len, str));
|
||||
}
|
||||
|
||||
/* We assume here that the string types that InnoDB itself can compare
|
||||
are single-byte charsets! */
|
||||
|
||||
if (prefix_len < data_len) {
|
||||
|
||||
return(prefix_len);
|
||||
|
||||
}
|
||||
|
||||
return(data_len);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a data main type is a string type. Also a BLOB is considered a
|
||||
string type. */
|
||||
|
|
|
@ -144,6 +144,29 @@ SQL null*/
|
|||
store the charset-collation number; one byte is left unused, though */
|
||||
#define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a string type has to be compared by the MySQL comparison functions.
|
||||
InnoDB internally only handles binary byte string comparisons, as well as
|
||||
latin1_swedish_ci strings. For example, UTF-8 strings have to be compared
|
||||
by MySQL. */
|
||||
|
||||
ibool
|
||||
dtype_str_needs_mysql_cmp(
|
||||
/*======================*/
|
||||
/* out: TRUE if a string type that requires
|
||||
comparison with MySQL functions */
|
||||
dtype_t* dtype); /* in: type struct */
|
||||
/*************************************************************************
|
||||
For the documentation of this function, see innobase_get_at_most_n_mbchars()
|
||||
in ha_innodb.cc. */
|
||||
|
||||
ulint
|
||||
dtype_get_at_most_n_mbchars(
|
||||
/*========================*/
|
||||
dtype_t* dtype,
|
||||
ulint prefix_len,
|
||||
ulint data_len,
|
||||
const char* str);
|
||||
/*************************************************************************
|
||||
Checks if a data main type is a string type. Also a BLOB is considered a
|
||||
string type. */
|
||||
|
|
|
@ -2019,16 +2019,12 @@ row_ins_index_entry_set_vals(
|
|||
if (ind_field->prefix_len > 0
|
||||
&& dfield_get_len(row_field) != UNIV_SQL_NULL) {
|
||||
|
||||
/* For prefix keys get the storage length
|
||||
for the prefix_len characters. */
|
||||
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(ind_field));
|
||||
|
||||
field->len = innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(cur_type->prtype),
|
||||
ind_field->prefix_len,
|
||||
dfield_get_len(row_field),row_field->data);
|
||||
field->len = dtype_get_at_most_n_mbchars(cur_type,
|
||||
ind_field->prefix_len,
|
||||
dfield_get_len(row_field), row_field->data);
|
||||
} else {
|
||||
field->len = row_field->len;
|
||||
}
|
||||
|
|
|
@ -143,18 +143,15 @@ row_build_index_entry(
|
|||
if (ind_field->prefix_len > 0
|
||||
&& dfield_get_len(dfield2) != UNIV_SQL_NULL) {
|
||||
|
||||
/* For prefix keys get the storage length
|
||||
for the prefix_len characters. */
|
||||
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(ind_field));
|
||||
|
||||
storage_len = innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(cur_type->prtype),
|
||||
storage_len = dtype_get_at_most_n_mbchars(
|
||||
cur_type,
|
||||
ind_field->prefix_len,
|
||||
dfield_get_len(dfield2),dfield2->data);
|
||||
dfield_get_len(dfield2), dfield2->data);
|
||||
|
||||
dfield_set_len(dfield,storage_len);
|
||||
dfield_set_len(dfield, storage_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,16 +494,13 @@ row_build_row_ref_from_row(
|
|||
if (field->prefix_len > 0
|
||||
&& dfield->len != UNIV_SQL_NULL) {
|
||||
|
||||
/* For prefix keys get the storage length
|
||||
for the prefix_len characters. */
|
||||
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(field));
|
||||
|
||||
dfield->len = innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(cur_type->prtype),
|
||||
dfield->len = dtype_get_at_most_n_mbchars(
|
||||
cur_type,
|
||||
field->prefix_len,
|
||||
dfield->len,dfield->data);
|
||||
dfield->len, dfield->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,16 +94,13 @@ row_sel_sec_rec_is_for_clust_rec(
|
|||
if (ifield->prefix_len > 0
|
||||
&& clust_len != UNIV_SQL_NULL) {
|
||||
|
||||
/* For prefix keys get the storage length
|
||||
for the prefix_len characters. */
|
||||
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(ifield));
|
||||
|
||||
clust_len = innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(cur_type->prtype),
|
||||
clust_len = dtype_get_at_most_n_mbchars(
|
||||
cur_type,
|
||||
ifield->prefix_len,
|
||||
clust_len,clust_field);
|
||||
clust_len, clust_field);
|
||||
}
|
||||
|
||||
if (0 != cmp_data_data(dict_col_get_type(col),
|
||||
|
|
|
@ -876,17 +876,15 @@ row_upd_index_replace_new_col_vals_index_pos(
|
|||
if (field->prefix_len > 0
|
||||
&& new_val->len != UNIV_SQL_NULL) {
|
||||
|
||||
/* For prefix keys get the storage length
|
||||
for the prefix_len characters. */
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(field));
|
||||
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(field));
|
||||
|
||||
dfield->len =
|
||||
innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(cur_type->prtype),
|
||||
field->prefix_len,
|
||||
new_val->len,new_val->data);
|
||||
dfield->len =
|
||||
dtype_get_at_most_n_mbchars(
|
||||
cur_type,
|
||||
field->prefix_len,
|
||||
new_val->len,
|
||||
new_val->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -948,17 +946,15 @@ row_upd_index_replace_new_col_vals(
|
|||
if (field->prefix_len > 0
|
||||
&& new_val->len != UNIV_SQL_NULL) {
|
||||
|
||||
/* For prefix keys get the storage length
|
||||
for the prefix_len characters. */
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(field));
|
||||
|
||||
cur_type = dict_col_get_type(
|
||||
dict_field_get_col(field));
|
||||
|
||||
dfield->len =
|
||||
innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(cur_type->prtype),
|
||||
field->prefix_len,
|
||||
new_val->len,new_val->data);
|
||||
dfield->len =
|
||||
dtype_get_at_most_n_mbchars(
|
||||
cur_type,
|
||||
field->prefix_len,
|
||||
new_val->len,
|
||||
new_val->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
-- disable_result_log
|
||||
--exec $TESTS_BINDIR/client_test --testcase --user=root --socket=var/tmp/master.sock --port=$MYSQL_TCP_PORT
|
||||
-- // exec $TESTS_BINDIR/client_test --testcase --user=root --socket=$MASTER_MYSOCK --port=$MYSQL_TCP_PORT
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
51
sql/field.cc
51
sql/field.cc
|
@ -2932,11 +2932,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 */
|
||||
|
@ -2952,23 +2953,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.
|
||||
|
||||
SYNOPSIS
|
||||
Field_timestamp::set_timestamp_offsets()
|
||||
|
||||
*/
|
||||
void Field_timestamp::set_timestamp_offsets()
|
||||
{
|
||||
ulong timestamp= (ulong) (ptr - (char*) table->record[0]) + 1;
|
||||
|
||||
DBUG_ASSERT(table->timestamp_field == this && unireg_check != NONE);
|
||||
Get auto-set type for TIMESTAMP field.
|
||||
|
||||
table->timestamp_default_now=
|
||||
(unireg_check == TIMESTAMP_UN_FIELD)? 0 : timestamp;
|
||||
table->timestamp_on_update_now=
|
||||
(unireg_check == TIMESTAMP_DN_FIELD)? 0 : timestamp;
|
||||
SYNOPSIS
|
||||
get_auto_set_type()
|
||||
|
||||
DESCRIPTION
|
||||
Returns value indicating during which operations this TIMESTAMP field
|
||||
should be auto-set to current timestamp.
|
||||
*/
|
||||
timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -3267,6 +3278,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)
|
||||
{
|
||||
|
@ -5985,8 +5997,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);
|
||||
|
|
|
@ -683,6 +683,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);
|
||||
|
@ -712,8 +713,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);
|
||||
|
@ -725,7 +729,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);
|
||||
}
|
||||
|
||||
|
|
103
sql/ha_innodb.cc
103
sql/ha_innodb.cc
|
@ -2240,8 +2240,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;
|
||||
|
@ -2612,8 +2612,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;
|
||||
|
@ -5258,8 +5258,7 @@ innobase_store_binlog_offset_and_flush_log(
|
|||
/*=============================*/
|
||||
char *binlog_name, /* in: binlog name */
|
||||
longlong offset /* in: binlog offset */
|
||||
)
|
||||
{
|
||||
) {
|
||||
mtr_t mtr;
|
||||
|
||||
assert(binlog_name != NULL);
|
||||
|
@ -5298,50 +5297,84 @@ ulonglong ha_innobase::get_mysql_bin_log_pos()
|
|||
|
||||
extern "C" {
|
||||
/**********************************************************************
|
||||
This function is used to find storage length of prefix_len characters
|
||||
in bytes for prefix indexes using multibyte character set.
|
||||
Function finds charset information and returns length of
|
||||
prefix_len characters in the index field in bytes. */
|
||||
This function is used to find the storage length in bytes of the first n
|
||||
characters for prefix indexes using a multibyte character set. The function
|
||||
finds charset information and returns length of prefix_len characters in the
|
||||
index field in bytes.
|
||||
|
||||
ulint innobase_get_at_most_n_mbchars(
|
||||
/*=================================*/
|
||||
NOTE: the prototype of this function is copied to data0type.c! If you change
|
||||
this function, you MUST change also data0type.c! */
|
||||
|
||||
ulint
|
||||
innobase_get_at_most_n_mbchars(
|
||||
/*===========================*/
|
||||
/* out: number of bytes occupied by the first
|
||||
n characters */
|
||||
ulint charset_id, /* in: character set id */
|
||||
ulint prefix_len, /* in: prefix length of the index */
|
||||
ulint data_len, /* in: length of the sting in bytes */
|
||||
const char *pos) /* in: character string */
|
||||
ulint prefix_len, /* in: prefix length in bytes of the index
|
||||
(this has to be divided by mbmaxlen to get the
|
||||
number of CHARACTERS n in the prefix) */
|
||||
ulint data_len, /* in: length of the string in bytes */
|
||||
const char* str) /* in: character string */
|
||||
{
|
||||
ulint byte_length; /* storage length, in bytes. */
|
||||
ulint char_length; /* character length in bytes */
|
||||
ulint n_chars; /* number of characters in prefix */
|
||||
CHARSET_INFO* charset; /* charset used in the field */
|
||||
|
||||
ut_ad(pos);
|
||||
byte_length = data_len;
|
||||
|
||||
charset = get_charset(charset_id,MYF(MY_WME));
|
||||
charset = get_charset(charset_id, MYF(MY_WME));
|
||||
|
||||
ut_ad(charset);
|
||||
ut_ad(charset->mbmaxlen);
|
||||
|
||||
/* Calculate the storage length of the one character in bytes and
|
||||
how many characters the prefix index contains */
|
||||
/* Calculate how many characters at most the prefix index contains */
|
||||
|
||||
char_length = byte_length / charset->mbmaxlen;
|
||||
prefix_len = prefix_len / charset->mbmaxlen;
|
||||
n_chars = prefix_len / charset->mbmaxlen;
|
||||
|
||||
/* If length of the string is greater than storage length of the
|
||||
one character, we have to find the storage position of the
|
||||
prefix_len character in the string */
|
||||
/* If the charset is multi-byte, then we must find the length of the
|
||||
first at most n chars in the string. If the string contains less
|
||||
characters than n, then we return the length to the end of the last
|
||||
full character. */
|
||||
|
||||
if (byte_length > char_length) {
|
||||
char_length = my_charpos(charset, pos,
|
||||
pos + byte_length, prefix_len);
|
||||
set_if_smaller(char_length, byte_length);
|
||||
}
|
||||
else {
|
||||
char_length = prefix_len;
|
||||
if (charset->mbmaxlen > 1) {
|
||||
/* ulint right_value; */
|
||||
|
||||
/* my_charpos() returns the byte length of the first n_chars
|
||||
characters, or the end of the last full character */
|
||||
|
||||
char_length = my_charpos(charset, str,
|
||||
str + data_len, n_chars);
|
||||
|
||||
/*################################################*/
|
||||
/* TODO: my_charpos sometimes returns a non-sensical value
|
||||
that is BIGGER than data_len: try to fix this bug partly with
|
||||
these heuristics. This is NOT a complete bug fix! */
|
||||
|
||||
if (char_length > data_len) {
|
||||
char_length = data_len;
|
||||
}
|
||||
/*################################################*/
|
||||
|
||||
/* printf("data_len %lu, n_chars %lu, char_len %lu\n",
|
||||
data_len, n_chars, char_length);
|
||||
if (data_len < n_chars) {
|
||||
right_value = data_len;
|
||||
} else {
|
||||
right_value = n_chars;
|
||||
}
|
||||
|
||||
if (right_value != char_length) {
|
||||
printf("ERRRRRROOORRRRRRRRRRRR!!!!!!!!!\n");
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
if (data_len < prefix_len) {
|
||||
char_length = data_len;
|
||||
} else {
|
||||
char_length = prefix_len;
|
||||
}
|
||||
}
|
||||
|
||||
return char_length;
|
||||
return(char_length);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1559,8 +1559,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)))
|
||||
|
@ -1709,9 +1709,9 @@ 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) &&
|
||||
(key_cmp(table->primary_key, old_data, new_data)))
|
||||
|
|
|
@ -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 ?
|
||||
|
@ -1285,7 +1286,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; }
|
||||
|
|
31
sql/table.h
31
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;
|
||||
|
@ -99,16 +109,19 @@ struct st_table {
|
|||
uint status; /* Used by postfix.. */
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue