1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

move away from TIMESTAMP_DNUN_FIELD/TIMESTAMP_DN_FIELD code

use the new approach with Field->default_value expressions.
But keep the old TIMESTAMP_UN_FIELD for ON UPDATE NOW().
This commit is contained in:
Sergei Golubchik
2016-07-24 15:12:54 +02:00
parent 12d2c4fcd0
commit cd51c7fb60
9 changed files with 84 additions and 170 deletions

View File

@@ -4920,12 +4920,12 @@ void Field_double::sql_type(String &res) const
field has NOW() as default and is updated when row changes, else it is field has NOW() as default and is updated when row changes, else it is
field which has 0 as default value and is not automatically updated. field which has 0 as default value and is not automatically updated.
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
automatically (TIMESTAMP DEFAULT NOW()) automatically (TIMESTAMP DEFAULT NOW()), not used in Field since 10.2.2
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
NOW() as default (but it may has 0 or some other const timestamp as NOW() as default (but it may has 0 or some other const timestamp as
default) (TIMESTAMP ON UPDATE NOW()). default) (TIMESTAMP ON UPDATE NOW()).
TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on
update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW()) update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW()), not used in Field since 10.2.2
NONE - field which is not auto-set on update with some other than NOW() NONE - field which is not auto-set on update with some other than NOW()
default value (TIMESTAMP DEFAULT 0). default value (TIMESTAMP DEFAULT 0).
@@ -4956,8 +4956,8 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
this field will be automaticly updated on insert. this field will be automaticly updated on insert.
*/ */
flags|= TIMESTAMP_FLAG; flags|= TIMESTAMP_FLAG;
if (unireg_check != TIMESTAMP_DN_FIELD)
flags|= ON_UPDATE_NOW_FLAG; flags|= ON_UPDATE_NOW_FLAG;
DBUG_ASSERT(unireg_check == TIMESTAMP_UN_FIELD);
} }
} }
@@ -10561,29 +10561,14 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
- The column didn't have a default expression - The column didn't have a default expression
*/ */
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) && if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
old_field->ptr != NULL && old_field->ptr != NULL && orig_field != NULL)
orig_field != NULL &&
!default_value)
{ {
bool default_now= false; if (orig_field->has_update_default_function())
if (real_type_with_now_as_default(sql_type))
{
// The SQL type of the new field allows a function default:
default_now= orig_field->has_insert_default_function();
bool update_now= orig_field->has_update_default_function();
if (default_now && update_now)
unireg_check= Field::TIMESTAMP_DNUN_FIELD;
else if (default_now)
unireg_check= Field::TIMESTAMP_DN_FIELD;
else if (update_now)
unireg_check= Field::TIMESTAMP_UN_FIELD; unireg_check= Field::TIMESTAMP_UN_FIELD;
}
if (!default_now) // Give a constant default
{
/* Get the value from default_values */ /* Get the value from default_values */
const uchar *dv= orig_field->table->s->default_values; const uchar *dv= orig_field->table->s->default_values;
if (!orig_field->is_null_in_record(dv)) if (!default_value && !orig_field->is_null_in_record(dv))
{ {
StringBuffer<MAX_FIELD_WIDTH> tmp(charset); StringBuffer<MAX_FIELD_WIDTH> tmp(charset);
String *res= orig_field->val_str(&tmp, orig_field->ptr_in_record(dv)); String *res= orig_field->val_str(&tmp, orig_field->ptr_in_record(dv));
@@ -10597,7 +10582,6 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
} }
} }
} }
}
/** /**

View File

@@ -473,20 +473,6 @@ inline bool is_temporal_type_with_date(enum_field_types type)
} }
/**
Tests if a field real type can have "DEFAULT CURRENT_TIMESTAMP"
@param type Field type, as returned by field->real_type().
@retval true If field real type can have "DEFAULT CURRENT_TIMESTAMP".
@retval false If field real type can not have "DEFAULT CURRENT_TIMESTAMP".
*/
inline bool real_type_with_now_as_default(enum_field_types type)
{
return type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_TIMESTAMP2 ||
type == MYSQL_TYPE_DATETIME || type == MYSQL_TYPE_DATETIME2;
}
/** /**
Recognizer for concrete data type (called real_type for some reason), Recognizer for concrete data type (called real_type for some reason),
returning true if it is one of the TIMESTAMP types. returning true if it is one of the TIMESTAMP types.
@@ -928,16 +914,9 @@ public:
} }
virtual void set_default(); virtual void set_default();
bool has_insert_default_function() const
{
return (unireg_check == TIMESTAMP_DN_FIELD ||
unireg_check == TIMESTAMP_DNUN_FIELD);
}
bool has_update_default_function() const bool has_update_default_function() const
{ {
return (unireg_check == TIMESTAMP_UN_FIELD || return unireg_check == TIMESTAMP_UN_FIELD;
unireg_check == TIMESTAMP_DNUN_FIELD);
} }
/* /*
@@ -2377,21 +2356,7 @@ public:
void sql_type(String &str) const; void sql_type(String &str) const;
bool zero_pack() const { return 0; } bool zero_pack() const { return 0; }
virtual int set_time(); virtual int set_time();
virtual void set_default()
{
if (has_insert_default_function())
set_time();
else
Field::set_default();
}
virtual void set_explicit_default(Item *value); virtual void set_explicit_default(Item *value);
virtual int evaluate_insert_default_function()
{
int res= 0;
if (has_insert_default_function())
res= set_time();
return res;
}
virtual int evaluate_update_default_function() virtual int evaluate_update_default_function()
{ {
int res= 0; int res= 0;
@@ -2821,20 +2786,6 @@ public:
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{ return Field_datetime::get_TIME(ltime, ptr, fuzzydate); } { return Field_datetime::get_TIME(ltime, ptr, fuzzydate); }
virtual int set_time(); virtual int set_time();
virtual void set_default()
{
if (has_insert_default_function())
set_time();
else
Field::set_default();
}
virtual int evaluate_insert_default_function()
{
int res= 0;
if (has_insert_default_function())
res= set_time();
return res;
}
virtual int evaluate_update_default_function() virtual int evaluate_update_default_function()
{ {
int res= 0; int res= 0;
@@ -3813,9 +3764,7 @@ public:
bool has_default_function() const bool has_default_function() const
{ {
return (unireg_check == Field::TIMESTAMP_DN_FIELD || return (unireg_check == Field::TIMESTAMP_UN_FIELD ||
unireg_check == Field::TIMESTAMP_DNUN_FIELD ||
unireg_check == Field::TIMESTAMP_UN_FIELD ||
unireg_check == Field::NEXT_NUMBER); unireg_check == Field::NEXT_NUMBER);
} }

View File

@@ -956,8 +956,7 @@ bool Item_field::check_field_expression_processor(void *arg)
{ {
if (field->flags & NO_DEFAULT_VALUE_FLAG) if (field->flags & NO_DEFAULT_VALUE_FLAG)
return 0; return 0;
if ((field->default_value && field->default_value->flags) if ((field->default_value && field->default_value->flags) || field->vcol_info)
|| field->has_insert_default_function() || field->vcol_info)
{ {
Field *org_field= (Field*) arg; Field *org_field= (Field*) arg;
if (field == org_field || if (field == org_field ||
@@ -8258,7 +8257,7 @@ void Item_default_value::print(String *str, enum_query_type query_type)
void Item_default_value::calculate() void Item_default_value::calculate()
{ {
if (field->default_value || field->has_insert_default_function()) if (field->default_value)
field->set_default(); field->set_default();
} }

View File

@@ -2489,8 +2489,8 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
(*field)->default_value= vcol; (*field)->default_value= vcol;
*dfield_ptr++= *field; *dfield_ptr++= *field;
} }
if ((*field)->has_insert_default_function() || else
(*field)->has_update_default_function()) if ((*field)->has_update_default_function())
*dfield_ptr++= *field; *dfield_ptr++= *field;
} }
if (vfield) if (vfield)

View File

@@ -1634,20 +1634,11 @@ static bool get_field_default_value(THD *thd, Field *field, String *def_value,
bool quoted) bool quoted)
{ {
bool has_default; bool has_default;
bool has_now_default;
enum enum_field_types field_type= field->type(); enum enum_field_types field_type= field->type();
/*
We are using CURRENT_TIMESTAMP instead of NOW because it is
more standard
*/
has_now_default= field->has_insert_default_function();
has_default= (field->default_value || has_default= (field->default_value ||
(!(field->flags & NO_DEFAULT_VALUE_FLAG) && (!(field->flags & NO_DEFAULT_VALUE_FLAG) &&
field->unireg_check != Field::NEXT_NUMBER && field->unireg_check != Field::NEXT_NUMBER));
!((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))
&& has_now_default)));
def_value->length(0); def_value->length(0);
if (has_default) if (has_default)
@@ -1662,17 +1653,14 @@ static bool get_field_default_value(THD *thd, Field *field, String *def_value,
field->default_value->expr_str.length); field->default_value->expr_str.length);
def_value->append(')'); def_value->append(')');
} }
else if (field->unireg_check)
def_value->append(field->default_value->expr_str.str,
field->default_value->expr_str.length);
else else
def_value->set(field->default_value->expr_str.str, def_value->set(field->default_value->expr_str.str,
field->default_value->expr_str.length, field->default_value->expr_str.length,
&my_charset_utf8mb4_general_ci); &my_charset_utf8mb4_general_ci);
} }
else if (has_now_default)
{
def_value->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
if (field->decimals() > 0)
def_value->append_parenthesized(field->decimals());
}
else if (!field->is_null()) else if (!field->is_null())
{ // Not null by default { // Not null by default
char tmp[MAX_FIELD_WIDTH]; char tmp[MAX_FIELD_WIDTH];
@@ -1704,13 +1692,13 @@ static bool get_field_default_value(THD *thd, Field *field, String *def_value,
if (quoted) if (quoted)
append_unescaped(def_value, def_val.ptr(), def_val.length()); append_unescaped(def_value, def_val.ptr(), def_val.length());
else else
def_value->append(def_val.ptr(), def_val.length()); def_value->move(def_val);
} }
else if (quoted) else if (quoted)
def_value->append(STRING_WITH_LEN("''")); def_value->set(STRING_WITH_LEN("''"), system_charset_info);
} }
else if (field->maybe_null() && quoted) else if (field->maybe_null() && quoted)
def_value->append(STRING_WITH_LEN("NULL")); // Null as default def_value->set(STRING_WITH_LEN("NULL"), system_charset_info); // Null as default
else else
return 0; return 0;
@@ -1797,8 +1785,8 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
List<Item> field_list; List<Item> field_list;
char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH]; char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH];
const char *alias; const char *alias;
String type(tmp, sizeof(tmp), system_charset_info); String type;
String def_value(def_value_buf, sizeof(def_value_buf), system_charset_info); String def_value;
Field **ptr,*field; Field **ptr,*field;
uint primary_key; uint primary_key;
KEY *key_info; KEY *key_info;
@@ -1891,12 +1879,8 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" ")); packet->append(STRING_WITH_LEN(" "));
append_identifier(thd,packet,field->field_name, strlen(field->field_name)); append_identifier(thd,packet,field->field_name, strlen(field->field_name));
packet->append(' '); packet->append(' ');
// check for surprises from the previous call to Field::sql_type()
if (type.ptr() != tmp)
type.set(tmp, sizeof(tmp), system_charset_info);
else
type.set_charset(system_charset_info);
type.set(tmp, sizeof(tmp), system_charset_info);
field->sql_type(type); field->sql_type(type);
packet->append(type.ptr(), type.length(), system_charset_info); packet->append(type.ptr(), type.length(), system_charset_info);
@@ -1943,6 +1927,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" NULL")); packet->append(STRING_WITH_LEN(" NULL"));
} }
def_value.set(def_value_buf, sizeof(def_value_buf), system_charset_info);
if (get_field_default_value(thd, field, &def_value, 1)) if (get_field_default_value(thd, field, &def_value, 1))
{ {
packet->append(STRING_WITH_LEN(" DEFAULT ")); packet->append(STRING_WITH_LEN(" DEFAULT "));

View File

@@ -9670,8 +9670,7 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
Old fields keep their current values, and therefore should not be Old fields keep their current values, and therefore should not be
present in the set of autoupdate fields. present in the set of autoupdate fields.
*/ */
if ((*ptr)->default_value || if ((*ptr)->default_value)
((*ptr)->has_insert_default_function()))
{ {
*(dfield_ptr++)= *ptr; *(dfield_ptr++)= *ptr;
++to->s->default_fields; ++to->s->default_fields;

View File

@@ -66,7 +66,7 @@ LEX_STRING SLOW_LOG_NAME= {C_STRING_WITH_LEN("slow_log")};
Keyword added as a prefix when parsing the defining expression for a Keyword added as a prefix when parsing the defining expression for a
virtual column read from the column definition saved in the frm file virtual column read from the column definition saved in the frm file
*/ */
LEX_STRING parse_vcol_keyword= { C_STRING_WITH_LEN("PARSE_VCOL_EXPR ") }; static LEX_STRING parse_vcol_keyword= { C_STRING_WITH_LEN("PARSE_VCOL_EXPR ") };
static int64 last_table_id; static int64 last_table_id;
@@ -1551,6 +1551,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
LEX_STRING comment; LEX_STRING comment;
Virtual_column_info *vcol_info= 0; Virtual_column_info *vcol_info= 0;
uint gis_length, gis_decimals, srid= 0; uint gis_length, gis_decimals, srid= 0;
Field::utype unireg_check;
if (new_frm_ver >= 3) if (new_frm_ver >= 3)
{ {
@@ -1766,22 +1767,36 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
swap_variables(uint, null_bit_pos, mysql57_vcol_null_bit_pos); swap_variables(uint, null_bit_pos, mysql57_vcol_null_bit_pos);
} }
/* Convert pre-10.2.2 timestamps to use Field::default_value */
unireg_check= (Field::utype) MTYP_TYPENR(unireg_type);
if (unireg_check == Field::TIMESTAMP_DNUN_FIELD)
unireg_check= Field::TIMESTAMP_UN_FIELD;
if (unireg_check == Field::TIMESTAMP_DN_FIELD)
unireg_check= Field::NONE;
*field_ptr= reg_field= *field_ptr= reg_field=
make_field(share, &share->mem_root, record+recpos, make_field(share, &share->mem_root, record+recpos, (uint32) field_length,
(uint32) field_length, null_pos, null_bit_pos, pack_flag, field_type, charset,
null_pos, null_bit_pos, geom_type, srid, unireg_check,
pack_flag, (interval_nr ? share->intervals+interval_nr-1 : NULL),
field_type,
charset,
geom_type, srid,
(Field::utype) MTYP_TYPENR(unireg_type),
(interval_nr ?
share->intervals+interval_nr-1 :
(TYPELIB*) 0),
share->fieldnames.type_names[i]); share->fieldnames.type_names[i]);
if (!reg_field) // Not supported field type if (!reg_field) // Not supported field type
goto err; goto err;
if (unireg_check != (Field::utype) MTYP_TYPENR(unireg_type))
{
char buf[32];
if (reg_field->decimals())
my_snprintf(buf, sizeof(buf), "CURRENT_TIMESTAMP(%d)", reg_field->decimals());
else
strmov(buf, "CURRENT_TIMESTAMP");
reg_field->default_value= new (&share->mem_root) Virtual_column_info();
reg_field->default_value->stored_in_db= 1;
thd->make_lex_string(&reg_field->default_value->expr_str, buf, strlen(buf));
share->default_expressions++;
}
reg_field->field_index= i; reg_field->field_index= i;
reg_field->comment=comment; reg_field->comment=comment;
reg_field->vcol_info= vcol_info; reg_field->vcol_info= vcol_info;
@@ -1821,14 +1836,13 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (share->stored_rec_length>=recpos) if (share->stored_rec_length>=recpos)
share->stored_rec_length= recpos-1; share->stored_rec_length= recpos-1;
} }
if (reg_field->has_insert_default_function())
has_insert_default_function= 1;
if (reg_field->has_update_default_function()) if (reg_field->has_update_default_function())
{
has_update_default_function= 1; has_update_default_function= 1;
if (reg_field->has_insert_default_function() || if (!reg_field->default_value)
reg_field->has_update_default_function())
share->default_fields++; share->default_fields++;
} }
}
*field_ptr=0; // End marker *field_ptr=0; // End marker
/* Sanity checks: */ /* Sanity checks: */
DBUG_ASSERT(share->fields>=share->stored_fields); DBUG_ASSERT(share->fields>=share->stored_fields);
@@ -2213,16 +2227,19 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
} }
case 1: // Generated stored field case 1: // Generated stored field
vcol_info->stored_in_db= 1; vcol_info->stored_in_db= 1;
DBUG_ASSERT(!reg_field->vcol_info);
reg_field->vcol_info= vcol_info; reg_field->vcol_info= vcol_info;
share->virtual_fields++; share->virtual_fields++;
share->virtual_stored_fields++; // For insert/load data share->virtual_stored_fields++; // For insert/load data
break; break;
case 2: // Default expression case 2: // Default expression
vcol_info->stored_in_db= 1; vcol_info->stored_in_db= 1;
DBUG_ASSERT(!reg_field->default_value);
reg_field->default_value= vcol_info; reg_field->default_value= vcol_info;
share->default_expressions++; share->default_expressions++;
break; break;
case 3: // Field check constraint case 3: // Field check constraint
DBUG_ASSERT(!reg_field->check_constraint);
reg_field->check_constraint= vcol_info; reg_field->check_constraint= vcol_info;
share->field_check_constraints++; share->field_check_constraints++;
break; break;
@@ -2693,14 +2710,10 @@ Virtual_column_info *unpack_vcol_info_from_frm(THD *thd,
vcol_expr->length + vcol_expr->length +
parse_vcol_keyword.length + 3))) parse_vcol_keyword.length + 3)))
DBUG_RETURN(0); DBUG_RETURN(0);
memcpy(vcol_expr_str, memcpy(vcol_expr_str, parse_vcol_keyword.str, parse_vcol_keyword.length);
(char*) parse_vcol_keyword.str,
parse_vcol_keyword.length);
str_len= parse_vcol_keyword.length; str_len= parse_vcol_keyword.length;
vcol_expr_str[str_len++]= '('; vcol_expr_str[str_len++]= '(';
memcpy(vcol_expr_str + str_len, memcpy(vcol_expr_str + str_len, vcol_expr->str, vcol_expr->length);
(char*) vcol_expr->str,
vcol_expr->length);
str_len+= vcol_expr->length; str_len+= vcol_expr->length;
vcol_expr_str[str_len++]= ')'; vcol_expr_str[str_len++]= ')';
vcol_expr_str[str_len++]= 0; vcol_expr_str[str_len++]= 0;
@@ -3045,8 +3058,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
*(dfield_ptr++)= *field_ptr; *(dfield_ptr++)= *field_ptr;
} }
else else
if ((field->has_insert_default_function() || if (field->has_update_default_function())
field->has_update_default_function()))
*(dfield_ptr++)= *field_ptr; *(dfield_ptr++)= *field_ptr;
} }
@@ -6275,7 +6287,7 @@ void TABLE::mark_columns_needed_for_update()
to compare records and detect data change. to compare records and detect data change.
*/ */
if ((file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) && if ((file->ha_table_flags() & HA_PARTIAL_COLUMN_READ) &&
default_field && has_default_function(true)) default_field && s->has_update_default_function)
bitmap_union(read_set, write_set); bitmap_union(read_set, write_set);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@@ -6573,17 +6585,13 @@ void TABLE::mark_default_fields_for_write(bool is_insert)
for (field_ptr= default_field; *field_ptr; field_ptr++) for (field_ptr= default_field; *field_ptr; field_ptr++)
{ {
field= (*field_ptr); field= (*field_ptr);
if (field->default_value) if (is_insert && field->default_value)
{
if (is_insert)
{ {
bitmap_set_bit(write_set, field->field_index); bitmap_set_bit(write_set, field->field_index);
field->default_value->expr_item-> field->default_value->expr_item->
walk(&Item::register_field_in_read_map, 1, 0); walk(&Item::register_field_in_read_map, 1, 0);
} }
} else if (!is_insert && field->has_update_default_function())
else if ((is_insert && field->has_insert_default_function()) ||
(!is_insert && field->has_update_default_function()))
bitmap_set_bit(write_set, field->field_index); bitmap_set_bit(write_set, field->field_index);
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;

View File

@@ -685,7 +685,6 @@ struct TABLE_SHARE
bool virtual_stored_fields; bool virtual_stored_fields;
bool check_set_initialized; bool check_set_initialized;
bool has_update_default_function; bool has_update_default_function;
bool has_insert_default_function;
ulong table_map_id; /* for row-based replication */ ulong table_map_id; /* for row-based replication */
/* /*
@@ -1311,18 +1310,6 @@ public:
void mark_columns_used_by_check_constraints(void); void mark_columns_used_by_check_constraints(void);
void mark_check_constraint_columns_for_read(void); void mark_check_constraint_columns_for_read(void);
int verify_constraints(bool ignore_failure); int verify_constraints(bool ignore_failure);
/**
Check if a table has a default function either for INSERT or UPDATE-like
operation
@retval true there is a default function
@retval false there is no default function
*/
inline bool has_default_function(bool is_update)
{
return (is_update ?
s->has_update_default_function :
s->has_insert_default_function);
}
inline void column_bitmaps_set(MY_BITMAP *read_set_arg, inline void column_bitmaps_set(MY_BITMAP *read_set_arg,
MY_BITMAP *write_set_arg) MY_BITMAP *write_set_arg)
{ {

View File

@@ -1039,7 +1039,10 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
field->sql_type, field->sql_type,
field->charset, field->charset,
field->geom_type, field->srid, field->geom_type, field->srid,
field->unireg_check, field->unireg_check == Field::TIMESTAMP_DNUN_FIELD
? Field::TIMESTAMP_UN_FIELD
: field->unireg_check == Field::TIMESTAMP_DN_FIELD
? Field::NONE : field->unireg_check,
field->save_interval ? field->save_interval : field->save_interval ? field->save_interval :
field->interval, field->interval,
field->field_name); field->field_name);