summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2016-11-07 17:17:40 +0100
committerSergei Golubchik <serg@mariadb.org>2016-12-12 20:35:41 +0100
commita411d7f4f670c24b43b50f7d2a1129e10218f4a7 (patch)
treecc1e9cdf6b85bdcec8c0369e502d4d211b2f7263 /sql
parent8b3b6dc377c548b1b72978a015af999cf6e99760 (diff)
downloadmariadb-git-a411d7f4f670c24b43b50f7d2a1129e10218f4a7.tar.gz
store/show vcols as item->print()
otherwise we'd need to store sql_mode *per vcol* (consider CREATE INDEX...) and how SHOW CREATE TABLE would support that? Additionally, get rid of vcol::expr_str, just to make sure the string is always generated and never leaked in the original form.
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc40
-rw-r--r--sql/field.h70
-rw-r--r--sql/item.cc86
-rw-r--r--sql/item.h7
-rw-r--r--sql/item_timefunc.cc20
-rw-r--r--sql/item_timefunc.h4
-rw-r--r--sql/mysqld.h14
-rw-r--r--sql/share/errmsg-utf8.txt4
-rw-r--r--sql/sql_insert.cc69
-rw-r--r--sql/sql_show.cc57
-rw-r--r--sql/sql_string.cc2
-rw-r--r--sql/sql_string.h6
-rw-r--r--sql/sql_table.cc44
-rw-r--r--sql/sql_yacc.yy43
-rw-r--r--sql/table.cc401
-rw-r--r--sql/table.h8
-rw-r--r--sql/unireg.cc262
17 files changed, 535 insertions, 602 deletions
diff --git a/sql/field.cc b/sql/field.cc
index be6259e6a11..88af4f321dd 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -4956,8 +4956,8 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
this field will be automaticly updated on insert.
*/
flags|= TIMESTAMP_FLAG;
- flags|= ON_UPDATE_NOW_FLAG;
- DBUG_ASSERT(unireg_check == TIMESTAMP_UN_FIELD);
+ if (unireg_check != TIMESTAMP_DN_FIELD)
+ flags|= ON_UPDATE_NOW_FLAG;
}
}
@@ -9773,35 +9773,32 @@ void Column_definition::create_length_to_internal_length(void)
}
-bool check_expression(Virtual_column_info *vcol, const char *type,
- const char *name, bool must_be_determinstic)
+bool check_expression(Virtual_column_info *vcol, const char *name,
+ enum_vcol_info_type type)
+
{
bool ret;
Item::vcol_func_processor_result res;
- /* We use 2 bytes to store the expression length */
- if (vcol->expr_str.length > UINT_MAX32)
- {
- my_error(ER_EXPRESSION_IS_TOO_BIG, MYF(0), type, name);
- return TRUE;
- }
+
+ if (!vcol->name.length)
+ vcol->name.str= const_cast<char*>(name);
/*
Walk through the Item tree checking if all items are valid
to be part of the virtual column
*/
-
res.errors= 0;
ret= vcol->expr_item->walk(&Item::check_vcol_func_processor, 0, &res);
vcol->flags= res.errors;
uint filter= VCOL_IMPOSSIBLE;
- if (must_be_determinstic)
+ if (type != VCOL_GENERATED_VIRTUAL && type != VCOL_DEFAULT)
filter|= VCOL_NOT_STRICTLY_DETERMINISTIC;
if (ret || (res.errors & filter))
{
my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), res.name,
- type, name);
+ vcol_type_name(type), name);
return TRUE;
}
/*
@@ -9826,20 +9823,19 @@ bool Column_definition::check(THD *thd)
{
DBUG_ASSERT(vcol_info->expr_item);
vcol_info->set_field_type(sql_type);
- if (check_expression(vcol_info, "GENERATED ALWAYS AS", field_name,
- vcol_info->stored_in_db))
+ if (check_expression(vcol_info, field_name, vcol_info->stored_in_db
+ ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL))
DBUG_RETURN(TRUE);
}
if (check_constraint &&
- check_expression(check_constraint, "CHECK", field_name, 0))
- DBUG_RETURN(1);
+ check_expression(check_constraint, field_name, VCOL_CHECK_FIELD))
+ DBUG_RETURN(1);
if (default_value)
{
Item *def_expr= default_value->expr_item;
-
- if (check_expression(default_value, "DEFAULT", field_name, 0))
+ if (check_expression(default_value, field_name, VCOL_DEFAULT))
DBUG_RETURN(TRUE);
/* Constant's are stored in the 'empty_record', except for blobs */
@@ -10556,8 +10552,8 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
if (!(flags & (NO_DEFAULT_VALUE_FLAG | BLOB_FLAG)) &&
old_field->ptr != NULL && orig_field != NULL)
{
- if (orig_field->has_update_default_function())
- unireg_check= Field::TIMESTAMP_UN_FIELD;
+ if (orig_field->unireg_check != Field::NEXT_NUMBER)
+ unireg_check= orig_field->unireg_check;
/* Get the value from default_values */
const uchar *dv= orig_field->table->s->default_values;
@@ -10567,8 +10563,6 @@ Column_definition::Column_definition(THD *thd, Field *old_field,
String *res= orig_field->val_str(&tmp, orig_field->ptr_in_record(dv));
char *pos= (char*) thd->strmake(res->ptr(), res->length());
default_value= new (thd->mem_root) Virtual_column_info();
- default_value->expr_str.str= pos;
- default_value->expr_str.length= res->length();
default_value->expr_item=
new (thd->mem_root) Item_string(thd, pos, res->length(), charset);
default_value->utf8= 0;
diff --git a/sql/field.h b/sql/field.h
index c44463248a3..83997c70032 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -560,6 +560,28 @@ inline bool is_temporal_type_with_time(enum_field_types type)
}
}
+enum enum_vcol_info_type
+{
+ VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED,
+ VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE
+};
+
+static inline const char *vcol_type_name(enum_vcol_info_type type)
+{
+ switch (type)
+ {
+ case VCOL_GENERATED_VIRTUAL:
+ case VCOL_GENERATED_STORED:
+ return "GENERATED ALWAYS AS";
+ case VCOL_DEFAULT:
+ return "DEFAULT";
+ case VCOL_CHECK_FIELD:
+ case VCOL_CHECK_TABLE:
+ return "CHECK";
+ }
+ return 0;
+}
+
/*
Flags for Virtual_column_info. If none is set, the expression must be
a constant with no side-effects, so it's calculated at CREATE TABLE time,
@@ -599,10 +621,7 @@ public:
/* Flag indicating that the field is physically stored in the database */
bool stored_in_db;
bool utf8; /* Already in utf8 */
- /* The expression to compute the value of the virtual column */
Item *expr_item;
- /* Text representation of the defining expression */
- LEX_STRING expr_str;
LEX_STRING name; /* Name of constraint */
uint flags;
@@ -611,7 +630,7 @@ public:
in_partitioning_expr(FALSE), stored_in_db(FALSE),
utf8(TRUE), expr_item(NULL), flags(0)
{
- expr_str.str= name.str= NULL;
+ name.str= NULL;
name.length= 0;
};
~Virtual_column_info() {}
@@ -640,13 +659,8 @@ public:
{
in_partitioning_expr= TRUE;
}
- bool is_equal(const Virtual_column_info* vcol) const
- {
- return field_type == vcol->get_real_type()
- && stored_in_db == vcol->is_stored()
- && expr_str.length == vcol->expr_str.length
- && memcmp(expr_str.str, vcol->expr_str.str, expr_str.length) == 0;
- }
+ inline bool is_equal(const Virtual_column_info* vcol) const;
+ void print(String*);
};
class Field: public Value_source
@@ -920,7 +934,12 @@ public:
bool has_update_default_function() const
{
- return unireg_check == TIMESTAMP_UN_FIELD;
+ return flags & ON_UPDATE_NOW_FLAG;
+ }
+ bool has_default_now_unireg_check() const
+ {
+ return unireg_check == TIMESTAMP_DN_FIELD
+ || unireg_check == TIMESTAMP_DNUN_FIELD;
}
/*
@@ -941,14 +960,6 @@ public:
virtual void set_explicit_default(Item *value);
/**
- Evaluates the @c INSERT default function and stores the result in the
- field. If no such function exists for the column, or the function is not
- valid for the column's data type, invoking this function has no effect.
- */
- virtual int evaluate_insert_default_function() { return 0; }
-
-
- /**
Evaluates the @c UPDATE default function, if one exists, and stores the
result in the record buffer. If no such function exists for the column,
or the function is not valid for the column's data type, invoking this
@@ -2785,7 +2796,11 @@ public:
const char *field_name_arg)
:Field_temporal_with_date(ptr_arg, length_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
- {}
+ {
+ if (unireg_check == TIMESTAMP_UN_FIELD ||
+ unireg_check == TIMESTAMP_DNUN_FIELD)
+ flags|= ON_UPDATE_NOW_FLAG;
+ }
enum_field_types type() const { return MYSQL_TYPE_DATETIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
double val_real(void);
@@ -3779,8 +3794,7 @@ public:
bool has_default_function() const
{
- return (unireg_check == Field::TIMESTAMP_UN_FIELD ||
- unireg_check == Field::NEXT_NUMBER);
+ return unireg_check != Field::NONE;
}
Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root,
@@ -3801,6 +3815,12 @@ public:
}
/* Return true if default is an expression that must be saved explicitely */
bool has_default_expression();
+
+ bool has_default_now_unireg_check() const
+ {
+ return unireg_check == Field::TIMESTAMP_DN_FIELD
+ || unireg_check == Field::TIMESTAMP_DNUN_FIELD;
+ }
};
@@ -3897,8 +3917,8 @@ uint32 calc_pack_length(enum_field_types type,uint32 length);
int set_field_to_null(Field *field);
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
int convert_null_to_field_value_or_error(Field *field);
-bool check_expression(Virtual_column_info *vcol, const char *type,
- const char *name, bool must_be_deterministic);
+bool check_expression(Virtual_column_info *vcol, const char *name,
+ enum_vcol_info_type type);
/*
The following are for the interface with the .frm file
diff --git a/sql/item.cc b/sql/item.cc
index 04c573ee8b4..c8cff0859c0 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2638,16 +2638,50 @@ void Item_ident::print(String *str, enum_query_type query_type)
THD *thd= current_thd;
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
const char *d_name= db_name, *t_name= table_name;
+ bool use_table_name= table_name && table_name[0];
+ bool use_db_name= use_table_name && db_name && db_name[0] && !alias_name_used;
+
+ if (use_db_name && (query_type & QT_ITEM_IDENT_SKIP_DB_NAMES))
+ use_db_name= !thd->db || strcmp(thd->db, db_name);
+
+ if (use_db_name)
+ use_db_name= !(cached_table && cached_table->belong_to_view &&
+ cached_table->belong_to_view->compact_view_format);
+
+ if (!use_db_name && use_table_name &&
+ (query_type & QT_ITEM_IDENT_SKIP_TABLE_NAMES))
+ {
+ /*
+ Don't print the table name if it's the only table in the context
+ XXX technically, that's a sufficient, but too strong condition
+ */
+ if (!context)
+ use_table_name= false;
+ else if (context->outer_context)
+ use_table_name= true;
+ else if (context->last_name_resolution_table == context->first_name_resolution_table)
+ use_table_name= false;
+ else if (!context->last_name_resolution_table &&
+ !context->first_name_resolution_table->next_name_resolution_table)
+ use_table_name= false;
+ }
+
+ if (!field_name || !field_name[0])
+ {
+ append_identifier(thd, str, STRING_WITH_LEN("tmp_field"));
+ return;
+ }
+
if (lower_case_table_names== 1 ||
(lower_case_table_names == 2 && !alias_name_used))
{
- if (table_name && table_name[0])
+ if (use_table_name)
{
strmov(t_name_buff, table_name);
my_casedn_str(files_charset_info, t_name_buff);
t_name= t_name_buff;
}
- if (db_name && db_name[0])
+ if (use_db_name)
{
strmov(d_name_buff, db_name);
my_casedn_str(files_charset_info, d_name_buff);
@@ -2655,43 +2689,18 @@ void Item_ident::print(String *str, enum_query_type query_type)
}
}
- if (!table_name || !field_name || !field_name[0])
- {
- const char *nm= (field_name && field_name[0]) ?
- field_name : name ? name : "tmp_field";
- append_identifier(thd, str, nm, (uint) strlen(nm));
- return;
- }
- if (db_name && db_name[0] && !alias_name_used)
+ if (use_db_name)
{
- /*
- When printing EXPLAIN, don't print database name when it's the same as
- current database.
- */
- bool skip_db= (query_type & QT_ITEM_IDENT_SKIP_CURRENT_DATABASE) &&
- thd->db && !strcmp(thd->db, db_name);
- if (!skip_db &&
- !(cached_table && cached_table->belong_to_view &&
- cached_table->belong_to_view->compact_view_format))
- {
- append_identifier(thd, str, d_name, (uint)strlen(d_name));
- str->append('.');
- }
- append_identifier(thd, str, t_name, (uint)strlen(t_name));
+ append_identifier(thd, str, d_name, (uint)strlen(d_name));
str->append('.');
- append_identifier(thd, str, field_name, (uint)strlen(field_name));
+ DBUG_ASSERT(use_table_name);
}
- else
+ if (use_table_name)
{
- if (table_name[0])
- {
- append_identifier(thd, str, t_name, (uint) strlen(t_name));
- str->append('.');
- append_identifier(thd, str, field_name, (uint) strlen(field_name));
- }
- else
- append_identifier(thd, str, field_name, (uint) strlen(field_name));
+ append_identifier(thd, str, t_name, (uint) strlen(t_name));
+ str->append('.');
}
+ append_identifier(thd, str, field_name, (uint) strlen(field_name));
}
/* ARGSUSED */
@@ -10442,3 +10451,12 @@ void Item::register_in(THD *thd)
next= thd->free_list;
thd->free_list= this;
}
+
+void Virtual_column_info::print(String *str)
+{
+ expr_item->print(str, (enum_query_type)(QT_ITEM_ORIGINAL_FUNC_NULLIF |
+ QT_ITEM_IDENT_SKIP_DB_NAMES |
+ QT_ITEM_IDENT_SKIP_TABLE_NAMES |
+ QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS |
+ QT_TO_SYSTEM_CHARSET));
+}
diff --git a/sql/item.h b/sql/item.h
index 1aa613a25b8..c3128b35c52 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2583,6 +2583,7 @@ public:
bool update_vcol_processor(void *arg);
bool check_vcol_func_processor(void *arg)
{
+ context= 0;
return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF);
}
void cleanup();
@@ -5783,5 +5784,11 @@ bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str,
bool escape_used_in_parsing, CHARSET_INFO *cmp_cs,
int *escape);
+inline bool Virtual_column_info::is_equal(const Virtual_column_info* vcol) const
+{
+ return field_type == vcol->get_real_type()
+ && stored_in_db == vcol->is_stored()
+ && expr_item->eq(vcol->expr_item, true);
+}
#endif /* SQL_ITEM_INCLUDED */
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index c35606781ec..a9aaf5dd241 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1651,6 +1651,15 @@ bool Item_func_curtime::get_date(MYSQL_TIME *res,
return 0;
}
+void Item_func_curtime::print(String *str, enum_query_type query_type)
+{
+ str->append(func_name());
+ str->append('(');
+ if (decimals)
+ str->append_ulonglong(decimals);
+ str->append(')');
+}
+
static void set_sec_part(ulong sec_part, MYSQL_TIME *ltime, Item *item)
{
DBUG_ASSERT(item->decimals == AUTO_SEC_PART_DIGITS ||
@@ -1704,6 +1713,15 @@ bool Item_func_now::fix_fields(THD *thd, Item **items)
return Item_temporal_func::fix_fields(thd, items);
}
+void Item_func_now::print(String *str, enum_query_type query_type)
+{
+ str->append(func_name());
+ str->append('(');
+ if (decimals)
+ str->append_ulonglong(decimals);
+ str->append(')');
+}
+
/**
Converts current time in my_time_t to MYSQL_TIME represenatation for local
time zone. Defines time zone (local) used for whole NOW function.
@@ -2336,7 +2354,7 @@ void Item_temporal_typecast::print(String *str, enum_query_type query_type)
args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as "));
str->append(cast_type());
- if (decimals)
+ if (decimals && decimals != NOT_FIXED_DEC)
{
str->append('(');
str->append(llstr(decimals, buf));
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 07b4ef92b2e..949401e19fd 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -655,6 +655,7 @@ public:
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC);
}
+ void print(String *str, enum_query_type query_type);
};
@@ -740,6 +741,7 @@ public:
*/
return mark_unsupported_function(func_name(), "()", arg, VCOL_TIME_FUNC);
}
+ void print(String *str, enum_query_type query_type);
};
@@ -747,7 +749,7 @@ class Item_func_now_local :public Item_func_now
{
public:
Item_func_now_local(THD *thd, uint dec): Item_func_now(thd, dec) {}
- const char *func_name() const { return "now"; }
+ const char *func_name() const { return "current_timestamp"; }
virtual void store_now_in_TIME(THD *thd, MYSQL_TIME *now_time);
virtual enum Functype functype() const { return NOW_FUNC; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 02bbdf839c1..96944c012ce 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -662,13 +662,15 @@ enum enum_query_type
QT_WITHOUT_INTRODUCERS= (1 << 1),
/// view internal representation (like QT_ORDINARY except ORDER BY clause)
QT_VIEW_INTERNAL= (1 << 2),
- /// If identifiers should not include database names for the current database
- QT_ITEM_IDENT_SKIP_CURRENT_DATABASE= (1 << 3),
+ /// If identifiers should not include database names, where unambiguous
+ QT_ITEM_IDENT_SKIP_DB_NAMES= (1 << 3),
+ /// If identifiers should not include table names, where unambiguous
+ QT_ITEM_IDENT_SKIP_TABLE_NAMES= (1 << 4),
/// If Item_cache_wrapper should not print <expr_cache>
- QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS= (1 << 4),
+ QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS= (1 << 5),
/// If Item_subselect should print as just "(subquery#1)"
/// rather than display the subquery body
- QT_ITEM_SUBSELECT_ID_ONLY= (1 << 5),
+ QT_ITEM_SUBSELECT_ID_ONLY= (1 << 6),
/// If NULLIF(a,b) should print itself as
/// CASE WHEN a_for_comparison=b THEN NULL ELSE a_for_return_value END
/// when "a" was replaced to two different items
@@ -678,11 +680,11 @@ enum enum_query_type
/// a_for_return_value is not the same as a_for_comparison.
/// SHOW CREATE {VIEW|PROCEDURE|FUNCTION} and other cases where the
/// original representation is required, should set this flag.
- QT_ITEM_ORIGINAL_FUNC_NULLIF= (1 <<6),
+ QT_ITEM_ORIGINAL_FUNC_NULLIF= (1 << 7),
/// This value means focus on readability, not on ability to parse back, etc.
QT_EXPLAIN= QT_TO_SYSTEM_CHARSET |
- QT_ITEM_IDENT_SKIP_CURRENT_DATABASE |
+ QT_ITEM_IDENT_SKIP_DB_NAMES |
QT_ITEM_CACHE_WRAPPER_SKIP_DETAILS |
QT_ITEM_SUBSELECT_ID_ONLY,
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 8f81d23816e..1fc22fa415f 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7395,9 +7395,9 @@ ER_CONSTRAINT_FAILED 23000
rus "проверка CONSTRAINT %`s для %`-.192s.%`-.192s провалилась"
ukr "Перевірка CONSTRAINT %`s для %`-.192s.%`-.192s не пройшла"
ER_EXPRESSION_IS_TOO_BIG
- eng "%s expression in the %s clause is too big"
+ eng "Expression in the %s clause is too big"
ER_ERROR_EVALUATING_EXPRESSION
- eng "Got an error evaluating stored expression %`s"
+ eng "Got an error evaluating stored expression %s"
ER_CALCULATING_DEFAULT_VALUE
eng "Got an error when calculating default value for %`s"
ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 01000
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 003fe4f5366..f918e547148 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -2353,6 +2353,12 @@ end_create:
DBUG_RETURN(thd->is_error());
}
+#define memdup_vcol(thd, vcol) \
+ if (vcol) \
+ { \
+ (vcol)= (Virtual_column_info*)(thd)->memdup((vcol), sizeof(*(vcol))); \
+ (vcol)->expr_item= NULL; \
+ }
/**
As we can't let many client threads modify the same TABLE
@@ -2374,7 +2380,6 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
{
my_ptrdiff_t adjust_ptrs;
Field **field,**org_field, *found_next_number_field;
- Field **vfield= 0, **dfield_ptr= 0;
TABLE *copy;
TABLE_SHARE *share;
uchar *bitmap;
@@ -2437,14 +2442,6 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
if (!copy_tmp)
goto error;
- if (share->virtual_fields)
- {
- vfield= (Field **) client_thd->alloc((share->virtual_fields+1)*
- sizeof(Field*));
- if (!vfield)
- goto error;
- }
-
/* Copy the TABLE object. */
copy= new (copy_tmp) TABLE;
*copy= *table;
@@ -2463,7 +2460,14 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
sizeof(Field*));
if (!copy->default_field)
goto error;
- dfield_ptr= copy->default_field;
+ }
+
+ if (share->virtual_fields)
+ {
+ copy->vfield= (Field **) client_thd->alloc((share->virtual_fields+1)*
+ sizeof(Field*));
+ if (!copy->vfield)
+ goto error;
}
copy->expr_arena= NULL;
@@ -2481,12 +2485,14 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
found_next_number_field= table->found_next_number_field;
for (org_field= table->field; *org_field; org_field++, field++)
{
- if (!(*field= (*org_field)->make_new_field(client_thd->mem_root, copy,
- 1)))
+ if (!(*field= (*org_field)->make_new_field(client_thd->mem_root, copy, 1)))
goto error;
(*field)->unireg_check= (*org_field)->unireg_check;
(*field)->orig_table= copy; // Remove connection
(*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0]
+ memdup_vcol(client_thd, (*field)->vcol_info);
+ memdup_vcol(client_thd, (*field)->default_value);
+ memdup_vcol(client_thd, (*field)->check_constraint);
if (*org_field == found_next_number_field)
(*field)->table->found_next_number_field= *field;
}
@@ -2499,42 +2505,9 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd)
if (!(copy->def_vcol_set= (MY_BITMAP*) alloc_root(client_thd->mem_root,
sizeof(MY_BITMAP))))
goto error;
- copy->vfield= vfield;
- for (field= copy->field; *field; field++)
- {
- Virtual_column_info *vcol;
- if ((*field)->vcol_info)
- {
- if (!(vcol= unpack_vcol_info_from_frm(client_thd,
- client_thd->mem_root,
- copy,
- 0,
- (*field)->vcol_info,
- &error_reported)))
- goto error;
- (*field)->vcol_info= vcol;
- *vfield++= *field;
- }
- if ((*field)->default_value)
- {
- if (!(vcol= unpack_vcol_info_from_frm(client_thd,
- client_thd->mem_root,
- copy,
- 0,
- (*field)->default_value,
- &error_reported)))
- goto error;
- (*field)->default_value= vcol;
- *dfield_ptr++= *field;
- }
- else
- if ((*field)->has_update_default_function())
- *dfield_ptr++= *field;
- }
- if (vfield)
- *vfield= 0;
- if (dfield_ptr)
- *dfield_ptr= 0;
+
+ if (parse_vcol_defs(client_thd, client_thd->mem_root, copy, &error_reported))
+ goto error;
}
switch_defaults_to_nullable_trigger_fields(copy);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 273615e1489..e2f9e9432af 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1635,9 +1635,11 @@ static bool print_on_update_clause(Field *field, String *val, bool lcase)
val->append(STRING_WITH_LEN("on update "));
else
val->append(STRING_WITH_LEN("ON UPDATE "));
- val->append(STRING_WITH_LEN("CURRENT_TIMESTAMP"));
+ val->append(STRING_WITH_LEN("current_timestamp"));
if (field->decimals() > 0)
val->append_parenthesized(field->decimals());
+ else
+ val->append(STRING_WITH_LEN("()"));
return true;
}
return false;
@@ -1657,51 +1659,42 @@ static bool get_field_default_value(THD *thd, Field *field, String *def_value,
def_value->length(0);
if (has_default)
{
+ StringBuffer<MAX_FIELD_WIDTH> str(field->charset());
if (field->default_value)
{
+ field->default_value->print(&str);
if (field->default_value->expr_item->need_parentheses_in_default())
{
def_value->set_charset(&my_charset_utf8mb4_general_ci);
def_value->append('(');
- def_value->append(field->default_value->expr_str.str,
- field->default_value->expr_str.length);
+ def_value->append(str);
def_value->append(')');
}
- else if (field->unireg_check)
- def_value->append(field->default_value->expr_str.str,
- field->default_value->expr_str.length);
else
- def_value->set(field->default_value->expr_str.str,
- field->default_value->expr_str.length,
- &my_charset_utf8mb4_general_ci);
+ def_value->append(str);
}
else if (!field->is_null())
{ // Not null by default
- char tmp[MAX_FIELD_WIDTH];
- String type(tmp, sizeof(tmp), field->charset());
if (field_type == MYSQL_TYPE_BIT)
{
- longlong dec= field->val_int();
- char *ptr= longlong2str(dec, tmp + 2, 2);
- uint32 length= (uint32) (ptr - tmp);
- tmp[0]= 'b';
- tmp[1]= '\'';
- tmp[length]= '\'';
- type.length(length + 1);
+ str.qs_append('b');
+ str.qs_append('\'');
+ str.qs_append(field->val_int(), 2);
+ str.qs_append('\'');
quoted= 0;
}
else
{
- field->val_str(&type);
+ field->val_str(&str);
if (!field->str_needs_quotes())
quoted= 0;
}
- if (type.length())
+ if (str.length())
{
- String def_val;
+ StringBuffer<MAX_FIELD_WIDTH> def_val;
uint dummy_errors;
/* convert to system_charset_info == utf8 */
- def_val.copy(type.ptr(), type.length(), field->charset(),
+ def_val.copy(str.ptr(), str.length(), field->charset(),
system_charset_info, &dummy_errors);
if (quoted)
append_unescaped(def_value, def_val.ptr(), def_val.length());
@@ -1918,10 +1911,10 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
if (field->vcol_info)
{
+ StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
+ field->vcol_info->print(&str);
packet->append(STRING_WITH_LEN(" AS ("));
- packet->append(field->vcol_info->expr_str.str,
- field->vcol_info->expr_str.length,
- &my_charset_utf8mb4_general_ci);
+ packet->append(str);
packet->append(STRING_WITH_LEN(")"));
if (field->vcol_info->stored_in_db)
packet->append(STRING_WITH_LEN(" PERSISTENT"));
@@ -1961,10 +1954,10 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
}
if (field->check_constraint)
{
+ StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
+ field->check_constraint->print(&str);
packet->append(STRING_WITH_LEN(" CHECK ("));
- packet->append(field->check_constraint->expr_str.str,
- field->check_constraint->expr_str.length,
- &my_charset_utf8mb4_general_ci);
+ packet->append(str);
packet->append(STRING_WITH_LEN(")"));
}
@@ -2062,7 +2055,9 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
for (uint i= share->field_check_constraints;
i < share->table_check_constraints ; i++)
{
+ StringBuffer<MAX_FIELD_WIDTH> str(&my_charset_utf8mb4_general_ci);
Virtual_column_info *check= table->check_constraints[i];
+ check->print(&str);
packet->append(STRING_WITH_LEN(",\n "));
if (check->name.length)
@@ -2071,9 +2066,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
append_identifier(thd, packet, check->name.str, check->name.length);
}
packet->append(STRING_WITH_LEN(" CHECK ("));
- packet->append(check->expr_str.str,
- check->expr_str.length,
- &my_charset_utf8mb4_general_ci);
+ packet->append(str);
packet->append(STRING_WITH_LEN(")"));
}
}
@@ -8447,7 +8440,7 @@ ST_FIELD_INFO columns_fields_info[]=
OPEN_FRM_ONLY},
{"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
{"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
- {"EXTRA", 27, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
+ {"EXTRA", 30, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
{"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
{"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
"Comment", OPEN_FRM_ONLY},
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 49442260704..62473e082c3 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -733,7 +733,7 @@ void String::qs_append(int i)
void String::qs_append(ulonglong i)
{
char *buff= Ptr + str_length;
- char *end= longlong10_to_str(i, buff,10);
+ char *end= longlong10_to_str(i, buff, 10);
str_length+= (int) (end-buff);
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 8be23184741..4b70675dca4 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -584,6 +584,12 @@ public:
qs_append((ulonglong)i);
}
void qs_append(ulonglong i);
+ void qs_append(longlong i, int radix)
+ {
+ char *buff= Ptr + str_length;
+ char *end= ll2str(i, buff, radix, 0);
+ str_length+= (int) (end-buff);
+ }
/* Inline (general) functions used by the protocol functions */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 5e93fac1ddd..1e985bc240b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3339,45 +3339,6 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (prepare_blob_field(thd, sql_field))
DBUG_RETURN(TRUE);
- if (sql_field->default_value)
- {
- Virtual_column_info *def= sql_field->default_value;
-
- if (!sql_field->has_default_expression())
- def->expr_str= null_lex_str;
-
- if (!def->expr_item->basic_const_item() && !def->flags)
- {
- Item *expr= def->expr_item;
- int err= !expr->fixed && // may be already fixed if ALTER TABLE
- expr->fix_fields(thd, &expr);
- if (!err)
- {
- if (expr->result_type() == REAL_RESULT)
- { // don't convert floats to string and back, it can be lossy
- double res= expr->val_real();
- if (expr->null_value)
- expr= new (thd->mem_root) Item_null(thd);
- else
- expr= new (thd->mem_root) Item_float(thd, res, expr->decimals);
- }
- else
- {
- StringBuffer<MAX_FIELD_WIDTH> buf;
- String *res= expr->val_str(&buf);
- if (expr->null_value)
- expr= new (thd->mem_root) Item_null(thd);
- else
- {
- char *str= (char*) thd->strmake(res->ptr(), res->length());
- expr= new (thd->mem_root) Item_string(thd, str, res->length(), res->charset());
- }
- }
- thd->change_item_tree(&def->expr_item, expr);
- }
- }
- }
-
/*
Convert the default value from client character
set into the column character set if necessary.
@@ -4205,11 +4166,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (check_string_char_length(&check->name, 0, NAME_CHAR_LEN,
system_charset_info, 1))
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str);
+ my_error(ER_TOO_LONG_IDENT, MYF(0), check->name.str);
DBUG_RETURN(TRUE);
}
- if (check_expression(check, "CONSTRAINT CHECK",
- check->name.str ? check->name.str : "", 0))
+ if (check_expression(check, check->name.str, VCOL_CHECK_TABLE))
DBUG_RETURN(TRUE);
}
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6c6895434e4..1885c2e5aa5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -910,27 +910,14 @@ bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin)
MYSQL_YYABORT; \
} while(0)
-Virtual_column_info *add_virtual_expression(THD *thd, const char *txt,
- size_t size, Item *expr)
+Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
{
- CHARSET_INFO *cs= thd->charset();
Virtual_column_info *v= new (thd->mem_root) Virtual_column_info();
if (!v)
{
mem_alloc_error(sizeof(Virtual_column_info));
return 0;
}
- /*
- We have to remove white space as remember_cur_pos may have pointed to end
- of previous expression.
- */
- while (cs->state_map[*(uchar*)txt] == MY_LEX_SKIP)
- {
- txt++;
- size--;
- }
- v->expr_str.str= (char* ) thd->strmake(txt, size);
- v->expr_str.length= size;
v->expr_item= expr;
v->utf8= 0; /* connection charset */
return v;
@@ -1761,7 +1748,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
table_ident_opt_wild create_like
%type <simple_string>
- remember_name remember_end opt_db remember_tok_start remember_cur_pos
+ remember_name remember_end opt_db remember_tok_start
wild_and_where
field_length opt_field_length opt_field_length_default_1
@@ -2005,7 +1992,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
definer_opt no_definer definer get_diagnostics
parse_vcol_expr vcol_opt_specifier vcol_opt_attribute
vcol_opt_attribute_list vcol_attribute
- explainable_command opt_impossible_action
+ explainable_command
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@@ -6120,10 +6107,10 @@ opt_check_constraint:
;
check_constraint:
- CHECK_SYM '(' remember_name expr remember_end ')'
+ CHECK_SYM '(' expr ')'
{
Virtual_column_info *v=
- add_virtual_expression(thd, $3+1, (uint)($5 - $3) - 1, $4);
+ add_virtual_expression(thd, $3);
if (!v)
{
MYSQL_YYABORT;
@@ -6264,10 +6251,10 @@ parenthesized_expr:
;
virtual_column_func:
- '(' remember_cur_pos parenthesized_expr remember_end ')'
+ '(' parenthesized_expr ')'
{
Virtual_column_info *v=
- add_virtual_expression(thd, $2, (uint)($4 - $2), $3);
+ add_virtual_expression(thd, $2);
if (!v)
{
MYSQL_YYABORT;
@@ -6280,19 +6267,13 @@ expr_or_literal: column_default_non_parenthesized_expr | signed_literal ;
column_default_expr:
virtual_column_func
- | remember_name expr_or_literal opt_impossible_action remember_end
+ | expr_or_literal
{
- if (!($$= add_virtual_expression(thd, $1, (uint) ($4- $1), $2)))
+ if (!($$= add_virtual_expression(thd, $1)))
MYSQL_YYABORT;
}
;
-/* This is to force remember_end to look at next token */
-opt_impossible_action:
- IMPOSSIBLE_ACTION {}
- | /* empty */ {}
-
-
field_type:
int_type opt_field_length field_options { $$.set($1, $2); }
| real_type opt_precision field_options { $$.set($1, $2); }
@@ -8747,12 +8728,6 @@ remember_tok_start:
}
;
-remember_cur_pos:
- {
- $$= (char*) YYLIP->get_cpp_ptr();
- }
- ;
-
remember_name:
{
$$= (char*) YYLIP->get_cpp_tok_start();
diff --git a/sql/table.cc b/sql/table.cc
index 6e54b6800e7..848352419d5 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -47,6 +47,9 @@
#define MYSQL57_GENERATED_FIELD 128
#define MYSQL57_GCOL_HEADER_SIZE 4
+static Virtual_column_info * unpack_vcol_info_from_frm(THD *, MEM_ROOT *,
+ TABLE *, const uchar *, size_t, Virtual_column_info *, bool *);
+static bool check_vcol_forward_refs(Field *, Virtual_column_info *);
/* INFORMATION_SCHEMA name */
LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
@@ -957,6 +960,159 @@ static void mysql57_calculate_null_position(TABLE_SHARE *share,
}
}
+
+/** Parse TABLE_SHARE::vcol_defs
+
+ unpack_vcol_info_from_frm
+ 5.7
+ byte 1 = 1
+ byte 2,3 = expr length
+ byte 4 = stored_in_db
+ expression
+ 10.1-
+ byte 1 = 1 | 2
+ byte 2 = sql_type
+ byte 3 = stored_in_db
+ [byte 4] = optional interval_id for sql_type (if byte 1 == 2)
+ expression
+ 10.2+
+ byte 1 = type
+ byte 2,3 = field_number
+ byte 4,5 = length of expression
+ byte 6 = length of name
+ name
+ expression
+*/
+bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
+ bool *error_reported)
+{
+ const uchar *pos= table->s->vcol_defs.str;
+ const uchar *end= pos + table->s->vcol_defs.length;
+ Field **field_ptr= table->field - 1;
+ Field **vfield_ptr= table->vfield;
+ Field **dfield_ptr= table->default_field;
+ Virtual_column_info **check_constraint_ptr= table->check_constraints;
+ Virtual_column_info *vcol;
+ DBUG_ENTER("parse_vcol_defs");
+
+ if (check_constraint_ptr)
+ memcpy(table->check_constraints + table->s->field_check_constraints,
+ table->s->check_constraints,
+ table->s->table_check_constraints * sizeof(Virtual_column_info*));
+
+ while (pos < end)
+ {
+ uint type, expr_length;
+ if (table->s->mysql_version >= 100202)
+ {
+ uint field_nr, name_length;
+ /* see pack_expression() for how data is stored */
+ type= pos[0];
+ field_nr= uint2korr(pos+1);
+ expr_length= uint2korr(pos+3);
+ name_length= pos[5];
+ pos+= FRM_VCOL_NEW_HEADER_SIZE + name_length;
+ field_ptr= table->field + field_nr;
+ }
+ else
+ {
+ /*
+ see below in ::init_from_binary_frm_image for how data is stored
+ in versions below 10.2 (that includes 5.7 too)
+ */
+ while (*++field_ptr && !(*field_ptr)->vcol_info) /* no-op */;
+ if (!*field_ptr)
+ {
+ open_table_error(table->s, OPEN_FRM_CORRUPTED, 1);
+ DBUG_RETURN(1);
+ }
+ type= (*field_ptr)->vcol_info->stored_in_db
+ ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL;
+ expr_length= uint2korr(pos+1);
+ if (table->s->mysql_version > 50700 && table->s->mysql_version < 100000)
+ pos+= 4; // MySQL from 5.7
+ else
+ pos+= pos[0] == 2 ? 4 : 3; // MariaDB from 5.2 to 10.1
+ }
+ switch (type) {
+ case VCOL_GENERATED_VIRTUAL:
+ case VCOL_GENERATED_STORED:
+ vcol= unpack_vcol_info_from_frm(thd, mem_root, table, pos, expr_length,
+ (*field_ptr)->vcol_info, error_reported);
+ DBUG_ASSERT((*field_ptr)->vcol_info->expr_item == NULL);
+ (*field_ptr)->vcol_info= vcol;
+ *(vfield_ptr++)= *field_ptr;
+ break;
+ case VCOL_DEFAULT:
+ vcol= unpack_vcol_info_from_frm(thd, mem_root, table, pos, expr_length,
+ (*field_ptr)->default_value,
+ error_reported);
+ DBUG_ASSERT((*field_ptr)->default_value->expr_item == NULL);
+ (*field_ptr)->default_value= vcol;
+ *(dfield_ptr++)= *field_ptr;
+ break;
+ case VCOL_CHECK_FIELD:
+ vcol= unpack_vcol_info_from_frm(thd, mem_root, table, pos, expr_length,
+ (*field_ptr)->check_constraint,
+ error_reported);
+ DBUG_ASSERT((*field_ptr)->check_constraint->expr_item == NULL);
+ (*field_ptr)->check_constraint= vcol;
+ *check_constraint_ptr++= vcol;
+ break;
+ case VCOL_CHECK_TABLE:
+ vcol= unpack_vcol_info_from_frm(thd, mem_root, table, pos, expr_length,
+ *check_constraint_ptr, error_reported);
+ *check_constraint_ptr++= vcol;
+ break;
+ }
+ if (!vcol)
+ DBUG_RETURN(1);
+ pos+= expr_length;
+ }
+
+ /* Now, initialize CURRENT_TIMESTAMP fields */
+ for (field_ptr= table->field; *field_ptr; field_ptr++)
+ {
+ Field *field= *field_ptr;
+ if (field->has_default_now_unireg_check())
+ {
+ char buf[256];
+ size_t len= my_snprintf(buf, sizeof(buf), "current_timestamp(%u)", field->decimals());
+ vcol= unpack_vcol_info_from_frm(thd, mem_root, table, (uchar*)buf, len,
+ (*field_ptr)->default_value,
+ error_reported);
+ DBUG_ASSERT((*field_ptr)->default_value->expr_item == NULL);
+ (*field_ptr)->default_value= vcol;
+ *(dfield_ptr++)= *field_ptr;
+ if (!field->default_value->expr_item)
+ DBUG_RETURN(1);
+ }
+ else if (field->has_update_default_function() && !field->default_value)
+ *(dfield_ptr++)= *field_ptr;
+ }
+
+ if (vfield_ptr)
+ *vfield_ptr= 0;
+
+ if (dfield_ptr)
+ *dfield_ptr= 0;
+
+ if (check_constraint_ptr)
+ *check_constraint_ptr= 0;
+
+ /* Check that expressions aren't refering to not yet initialized fields */
+ for (field_ptr= table->field; *field_ptr; field_ptr++)
+ {
+ Field *field= *field_ptr;
+ if (check_vcol_forward_refs(field, field->vcol_info) ||
+ check_vcol_forward_refs(field, field->check_constraint) ||
+ check_vcol_forward_refs(field, field->default_value))
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+}
+
/**
Read data from a binary .frm file image into a TABLE_SHARE
@@ -1452,6 +1608,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (!interval_count)
share->intervals= 0; // For better debugging
+ share->vcol_defs.str= vcol_screen_pos;
+ share->vcol_defs.length= vcol_screen_length;
+
memcpy(names, strpos+(share->fields*field_pack_length), n_length+int_length);
memcpy(comment_pos, disk_buff+read_length-com_length-vcol_screen_length,
com_length);
@@ -1535,8 +1694,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
mysql57_vcol_null_bit_pos= null_bit_pos;
mysql57_calculate_null_position(share, &mysql57_vcol_null_pos,
&mysql57_vcol_null_bit_pos,
- strpos,
- vcol_screen_pos);
+ strpos, vcol_screen_pos);
}
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
@@ -1631,18 +1789,20 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
{
unireg_type&= MYSQL57_GENERATED_FIELD;
+ /*
+ MySQL 5.7 generated fields
+
+ byte 1 = 1
+ byte 2,3 = expr length
+ byte 4 = stored_in_db
+ byte 5.. = expr
+ */
if ((uint)(vcol_screen_pos)[0] != 1)
goto err;
vcol_info= new (&share->mem_root) Virtual_column_info();
vcol_info_length= uint2korr(vcol_screen_pos + 1);
DBUG_ASSERT(vcol_info_length);
vcol_info->stored_in_db= vcol_screen_pos[3];
- if (!(vcol_info->expr_str.str=
- (char *)memdup_root(&share->mem_root,
- vcol_screen_pos + MYSQL57_GCOL_HEADER_SIZE,
- vcol_info_length)))
- goto err;
- vcol_info->expr_str.length= vcol_info_length;
vcol_info->utf8= 0;
vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;;
share->virtual_fields++;
@@ -1657,8 +1817,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
Get virtual column data stored in the .frm file as follows:
byte 1 = 1 | 2
byte 2 = sql_type
- byte 3 = flags (as of now, 0 - no flags,
- 1 - field is physically stored)
+ byte 3 = flags. 1 for stored_in_db
[byte 4] = optional interval_id for sql_type (if byte 1 == 2)
next byte ... = virtual column expression (text data)
*/
@@ -1670,20 +1829,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
interval_nr= (uint)vcol_screen_pos[3];
else if ((uint)vcol_screen_pos[0] != 1)
goto err;
-
- vcol_info->stored_in_db= vcol_screen_pos[2];
+ vcol_info->stored_in_db= vcol_screen_pos[2] & 1;
vcol_expr_length= vcol_info_length -
(uint)(FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id));
- if (!(vcol_info->expr_str.str=
- (char *)memdup_root(&share->mem_root,
- vcol_screen_pos +
- (uint) FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id),
- vcol_expr_length)))
- goto err;
- if (opt_interval_id)
- interval_nr= (uint) vcol_screen_pos[3];
- vcol_info->expr_str.length= vcol_expr_length;
vcol_info->utf8= 0; // before 10.2.1 the charset was unknown
+ int2store(vcol_screen_pos+1, vcol_expr_length); // for parse_vcol_defs()
vcol_screen_pos+= vcol_info_length;
share->virtual_fields++;
}
@@ -1768,11 +1918,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
/* 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=
make_field(share, &share->mem_root, record+recpos, (uint32) field_length,
null_pos, null_bit_pos, pack_flag, field_type, charset,
@@ -1782,17 +1927,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (!reg_field) // Not supported field type
goto err;
- if (unireg_check != (Field::utype) MTYP_TYPENR(unireg_type))
+ if (unireg_check == Field::TIMESTAMP_DNUN_FIELD ||
+ unireg_check == Field::TIMESTAMP_DN_FIELD)
{
- 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++;
}
@@ -1814,11 +1953,15 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
null_pos++;
}
- if (mysql57_null_bits && vcol_info && !vcol_info->stored_in_db)
+ if (vcol_info)
{
- /* MySQL 5.7 has null bits last */
- swap_variables(uchar*, null_pos, mysql57_vcol_null_pos);
- swap_variables(uint, null_bit_pos, mysql57_vcol_null_bit_pos);
+ vcol_info->name.str= const_cast<char*>(reg_field->field_name);
+ if (mysql57_null_bits && !vcol_info->stored_in_db)
+ {
+ /* MySQL 5.7 has null bits last */
+ swap_variables(uchar*, null_pos, mysql57_vcol_null_pos);
+ swap_variables(uint, null_bit_pos, mysql57_vcol_null_bit_pos);
+ }
}
if (f_no_default(pack_flag))
@@ -2169,6 +2312,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
/* Skip header */
vcol_screen_pos+= FRM_VCOL_NEW_BASE_SIZE;
+ share->vcol_defs.str+= FRM_VCOL_NEW_BASE_SIZE;
+ share->vcol_defs.length-= FRM_VCOL_NEW_BASE_SIZE;
/*
Read virtual columns, default values and check constraints
@@ -2181,40 +2326,28 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
uint field_nr= uint2korr(vcol_screen_pos+1);
uint expr_length= uint2korr(vcol_screen_pos+3);
uint name_length= (uint) vcol_screen_pos[5];
- LEX_STRING name;
- char *expr;
- vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE;
-
- name.str= 0;
- if ((name.length= name_length))
- {
- if (!(name.str= strmake_root(&share->mem_root,
- (char*) vcol_screen_pos,
- name_length)))
- goto err;
- }
- vcol_screen_pos+= name_length;
- if (!(vcol_info= new (&share->mem_root) Virtual_column_info()) ||
- !(expr= (char *) strmake_root(&share->mem_root,
- (char*) vcol_screen_pos,
- expr_length)))
+ if (!(vcol_info= new (&share->mem_root) Virtual_column_info()))
goto err;
- vcol_info->name= name;
-
/* The following can only be true for check_constraints */
+
if (field_nr != UINT_MAX16)
{
DBUG_ASSERT(field_nr < share->fields);
reg_field= share->field[field_nr];
}
- vcol_info->expr_str.str= expr;
- vcol_info->expr_str.length= expr_length;
- vcol_screen_pos+= expr_length;
+ vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE;
+ vcol_info->name.length= name_length;
+ if (name_length)
+ vcol_info->name.str= strmake_root(&share->mem_root,
+ (char*)vcol_screen_pos, name_length);
+ else
+ vcol_info->name.str= const_cast<char*>(reg_field->field_name);
+ vcol_screen_pos+= name_length + expr_length;
switch (type) {
- case 0: // Generated virtual field
+ case VCOL_GENERATED_VIRTUAL:
{
uint recpos;
reg_field->vcol_info= vcol_info;
@@ -2226,24 +2359,24 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->stored_rec_length= recpos-1;
break;
}
- case 1: // Generated stored field
+ case VCOL_GENERATED_STORED:
vcol_info->stored_in_db= 1;
DBUG_ASSERT(!reg_field->vcol_info);
reg_field->vcol_info= vcol_info;
share->virtual_fields++;
break;
- case 2: // Default expression
+ case VCOL_DEFAULT:
vcol_info->stored_in_db= 1;
DBUG_ASSERT(!reg_field->default_value);
reg_field->default_value= vcol_info;
share->default_expressions++;
break;
- case 3: // Field check constraint
+ case VCOL_CHECK_FIELD:
DBUG_ASSERT(!reg_field->check_constraint);
reg_field->check_constraint= vcol_info;
share->field_check_constraints++;
break;
- case 4: // Table check constraint
+ case VCOL_CHECK_TABLE:
*(table_check_constraints++)= vcol_info;
break;
}
@@ -2537,7 +2670,9 @@ static bool fix_vcol_expr(THD *thd, Virtual_column_info *vcol)
if (unlikely(error))
{
- my_error(ER_ERROR_EVALUATING_EXPRESSION, MYF(0), vcol->expr_str);
+ StringBuffer<MAX_FIELD_WIDTH> str;
+ vcol->print(&str);
+ my_error(ER_ERROR_EVALUATING_EXPRESSION, MYF(0), str.c_ptr());
DBUG_RETURN(1);
}
@@ -2609,7 +2744,7 @@ bool fix_session_vcol_expr_for_read(THD *thd, Field *field,
FALSE Otherwise
*/
-static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, Field *field,
+static bool fix_and_check_vcol_expr(THD *thd, TABLE *table,
Virtual_column_info *vcol)
{
Item* func_expr= vcol->expr_item;
@@ -2647,7 +2782,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, Field *field,
if (error || (res.errors & VCOL_IMPOSSIBLE))
{ // this can only happen if the frm was corrupted
my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), res.name,
- "???", field ? field->field_name : "?????");
+ "???", "?????");
DBUG_RETURN(1);
}
vcol->flags= res.errors;
@@ -2697,12 +2832,10 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, Field *field,
@retval NULL Error
*/
-Virtual_column_info *unpack_vcol_info_from_frm(THD *thd,
- MEM_ROOT *mem_root,
- TABLE *table,
- Field *field,
- Virtual_column_info *vcol,
- bool *error_reported)
+static Virtual_column_info *
+unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root, TABLE *table,
+ const uchar *expr_str, size_t expr_str_length,
+ Virtual_column_info *vcol, bool *error_reported)
{
char *vcol_expr_str;
int str_len;
@@ -2713,12 +2846,10 @@ Virtual_column_info *unpack_vcol_info_from_frm(THD *thd,
Create_field vcol_storage; // placeholder for vcol_info
Parser_state parser_state;
Virtual_column_info *vcol_info= 0;
- LEX_STRING *vcol_expr= &vcol->expr_str;
LEX *old_lex= thd->lex;
LEX lex;
bool error;
DBUG_ENTER("unpack_vcol_info_from_frm");
- DBUG_ASSERT(vcol_expr);
save_character_set_client= thd->variables.character_set_client;
save_collation= thd->variables.collation_connection;
@@ -2731,14 +2862,14 @@ Virtual_column_info *unpack_vcol_info_from_frm(THD *thd,
*/
if (!(vcol_expr_str= (char*) alloc_root(mem_root,
- vcol_expr->length +
+ expr_str_length +
parse_vcol_keyword.length + 3)))
DBUG_RETURN(0);
memcpy(vcol_expr_str, parse_vcol_keyword.str, parse_vcol_keyword.length);
str_len= parse_vcol_keyword.length;
vcol_expr_str[str_len++]= '(';
- memcpy(vcol_expr_str + str_len, vcol_expr->str, vcol_expr->length);
- str_len+= vcol_expr->length;
+ memcpy(vcol_expr_str + str_len, expr_str, expr_str_length);
+ str_len+= expr_str_length;
vcol_expr_str[str_len++]= ')';
vcol_expr_str[str_len++]= 0;
@@ -2787,7 +2918,7 @@ Virtual_column_info *unpack_vcol_info_from_frm(THD *thd,
vcol_storage.vcol_info->stored_in_db= vcol->stored_in_db;
vcol_storage.vcol_info->name= vcol->name;
vcol_storage.vcol_info->utf8= vcol->utf8;
- if (!fix_and_check_vcol_expr(thd, table, field, vcol_storage.vcol_info))
+ if (!fix_and_check_vcol_expr(thd, table, vcol_storage.vcol_info))
{
vcol_info= vcol_storage.vcol_info; // Expression ok
goto end;
@@ -3023,104 +3154,14 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
if (share->table_check_constraints || share->field_check_constraints)
outparam->check_constraints= check_constraint_ptr;
- /* Reuse the same loop both for virtual, default and check fields */
- for (field_ptr= outparam->field; *field_ptr; field_ptr++)
- {
- Field *field= *field_ptr;
- if (field->vcol_info)
- {
- Virtual_column_info *vcol;
- field->vcol_info->name.str= (char*) field->field_name;
- if (!(vcol= unpack_vcol_info_from_frm(thd, &outparam->mem_root,
- outparam, *field_ptr,
- field->vcol_info,
- &error_reported)))
- {
- error= OPEN_FRM_CORRUPTED;
- goto err;
- }
- field->vcol_info= vcol;
- *(vfield_ptr++)= *field_ptr;
- }
-
- if (field->check_constraint)
- {
- Virtual_column_info *vcol;
- field->check_constraint->name.str=
- (char*) field->field_name;
- if (!(vcol= unpack_vcol_info_from_frm(thd, &outparam->mem_root,
- outparam, 0,
- field->check_constraint,
- &error_reported)))
- {
- error= OPEN_FRM_CORRUPTED;
- goto err;
- }
- field->check_constraint= vcol;
- *(check_constraint_ptr++)= vcol;
- }
-
- if (field->default_value)
- {
- Virtual_column_info *vcol;
- field->default_value->name.str=
- (char*) field->field_name;
- if (!(vcol= unpack_vcol_info_from_frm(thd, &outparam->mem_root,
- outparam, *field_ptr,
- field->default_value,
- &error_reported)))
- {
- error= OPEN_FRM_CORRUPTED;
- goto err;
- }
- field->default_value= vcol;
- *(dfield_ptr++)= *field_ptr;
- }
- else
- if (field->has_update_default_function())
- *(dfield_ptr++)= *field_ptr;
-
- }
- *vfield_ptr= 0; // End marker
- *dfield_ptr= 0; // End marker
-
- /* Check that expressions aren't refering to not yet initialized fields */
- for (field_ptr= outparam->field; *field_ptr; field_ptr++)
+ if (parse_vcol_defs(thd, &outparam->mem_root, outparam, &error_reported))
{
- Field *field= *field_ptr;
- if (check_vcol_forward_refs(field, field->vcol_info) ||
- check_vcol_forward_refs(field, field->check_constraint) ||
- check_vcol_forward_refs(field, field->default_value))
- {
- error= OPEN_FRM_CORRUPTED;
- goto err;
- }
+ error= OPEN_FRM_CORRUPTED;
+ goto err;
}
/* Update to use trigger fields */
switch_defaults_to_nullable_trigger_fields(outparam);
-
- /* Copy table level constraints to check_constraint_ptr */
- for (i= 0 ;
- i < share->table_check_constraints - share->field_check_constraints;
- i++)
- {
- if (!(*check_constraint_ptr=
- unpack_vcol_info_from_frm(thd,
- &outparam->mem_root,
- outparam,
- 0,
- share->check_constraints[i],
- &error_reported)))
- {
- error= OPEN_FRM_CORRUPTED;
- goto err;
- }
- (*check_constraint_ptr)->name= share->check_constraints[i]->name;
- check_constraint_ptr++;
- }
-
- *check_constraint_ptr= 0; // End marker
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -3776,8 +3817,8 @@ rename_file_ext(const char * from,const char * to,const char * ext)
bool get_field(MEM_ROOT *mem, Field *field, String *res)
{
- char buff[MAX_FIELD_WIDTH], *to;
- String str(buff,sizeof(buff),&my_charset_bin);
+ char *to;
+ StringBuffer<MAX_FIELD_WIDTH> str;
bool rc;
THD *thd= field->get_thd();
sql_mode_t sql_mode_backup= thd->variables.sql_mode;
@@ -4060,13 +4101,11 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def)
is backward compatible.
*/
}
- char buffer[1024];
+ StringBuffer<1024> sql_type(system_charset_info);
+ sql_type.extra_allocation(256); // Allocate min 256 characters at once
for (i=0 ; i < table_def->count; i++, field_def++)
{
- String sql_type(buffer, sizeof(buffer), system_charset_info);
sql_type.length(0);
- /* Allocate min 256 characters at once */
- sql_type.extra_allocation(256);
if (i < table->s->fields)
{
Field *field= table->field[i];
@@ -7390,7 +7429,7 @@ int TABLE::update_virtual_field(Field *vf)
int TABLE::update_default_fields(bool update_command, bool ignore_errors)
{
- DBUG_ENTER("update_default_fields");
+ DBUG_ENTER("TABLE::update_default_fields");
Field **field_ptr;
int res= 0;
DBUG_ASSERT(default_field);
@@ -7412,8 +7451,6 @@ int TABLE::update_default_fields(bool update_command, bool ignore_errors)
if (field->default_value &&
(field->default_value->flags || field->flags & BLOB_FLAG))
res|= (field->default_value->expr_item->save_in_field(field, 0) < 0);
- else
- res|= field->evaluate_insert_default_function();
}
else
res|= field->evaluate_update_default_function();
diff --git a/sql/table.h b/sql/table.h
index 4ecc8f89b9e..c2c523181a0 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -582,6 +582,7 @@ struct TABLE_SHARE
KEY *key_info; /* data of keys in database */
Virtual_column_info **check_constraints;
uint *blob_field; /* Index to blobs in Field arrray*/
+ LEX_CUSTRING vcol_defs; /* definitions of generated columns */
TABLE_STATISTICS_CB stats_cb;
@@ -2668,11 +2669,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol);
bool fix_session_vcol_expr_for_read(THD *thd, Field *field,
Virtual_column_info *vcol);
-Virtual_column_info *unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root,
- TABLE *table,
- Field *field,
- Virtual_column_info *vcol,
- bool *error_reported);
+bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
+ bool *error_reported);
TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
const char *key, uint key_length);
void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 66fde186b5b..c102835a7bb 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -42,13 +42,11 @@
static uint pack_keys(uchar *,uint, KEY *, ulong);
static bool pack_header(THD *, uchar *, List<Create_field> &, HA_CREATE_INFO *,
ulong, handler *);
+static bool pack_vcols(String *, List<Create_field> &, List<Virtual_column_info> *);
static uint get_interval_id(uint *,List<Create_field> &, Create_field *);
static bool pack_fields(uchar **, List<Create_field> &, HA_CREATE_INFO*,
ulong);
-static void pack_constraints(uchar **buff, List<Virtual_column_info> *constr);
static size_t packed_fields_length(List<Create_field> &);
-static size_t packed_constraints_length(THD *, HA_CREATE_INFO*,
- List<Virtual_column_info> *);
static bool make_empty_rec(THD *, uchar *, uint, List<Create_field> &, uint,
ulong);
@@ -120,6 +118,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
int error;
uchar *frm_ptr, *pos;
LEX_CUSTRING frm= {0,0};
+ StringBuffer<MAX_FIELD_WIDTH> vcols;
DBUG_ENTER("build_frm_image");
/* If fixed row records, we need one bit to check for deleted rows */
@@ -127,9 +126,19 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
create_info->null_bits++;
data_offset= (create_info->null_bits + 7) / 8;
+ sql_mode_t save_sql_mode= thd->variables.sql_mode;
+ thd->variables.sql_mode &= ~MODE_ANSI_QUOTES;
+ error= pack_vcols(&vcols, create_fields, create_info->check_constraint_list);
+ thd->variables.sql_mode= save_sql_mode;
+
+ if (error)
+ DBUG_RETURN(frm);
+
+ if (vcols.length())
+ create_info->expression_length= vcols.length() + FRM_VCOL_NEW_BASE_SIZE;
+
error= pack_header(thd, forminfo, create_fields, create_info,
data_offset, db_file);
-
if (error)
DBUG_RETURN(frm);
@@ -336,6 +345,15 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
if (pack_fields(&pos, create_fields, create_info, data_offset))
goto err;
+ if (vcols.length())
+ {
+ /* Store header for packed fields (extra space for future) */
+ bzero(pos, FRM_VCOL_NEW_BASE_SIZE);
+ pos+= FRM_VCOL_NEW_BASE_SIZE;
+ memcpy(pos, vcols.ptr(), vcols.length());
+ pos+= vcols.length();
+ }
+
{
/*
Restore all UCS2 intervals.
@@ -496,92 +514,73 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
/**
- Calculate and check length of stored expression (virtual, def, check)
-
- Convert string to utf8, if it isn't already
+ Pack the expression (for GENERATED ALWAYS AS, DEFAULT, CHECK)
- @param thd Thread handler. Used for memory allocation
- @param v_col Virtual expression. Can be 0
- @param CREATE INFO For characterset
- @param length Sum total lengths here
-
- Note to make calls easier, one can call this with v_col == 0
+ The data is stored as:
+ 1 byte type (enum_vcol_info_type)
+ 2 bytes field_number
+ 2 bytes length of expression
+ 1 byte length of name
+ name
+ next bytes column expression (text data)
@return 0 ok
@return 1 error (out of memory or wrong characters in expression)
*/
-static bool add_expr_length(THD *thd, Virtual_column_info **v_col_ptr,
- size_t *length)
+static bool pack_expression(String *buf, Virtual_column_info *vcol,
+ uint field_nr, enum_vcol_info_type type)
{
- Virtual_column_info *v_col= *v_col_ptr;
- if (!v_col)
- return 0;
-
- /*
- Convert string to utf8 for storage.
- */
- if (!v_col->utf8)
- {
- /*
- This v_col comes from the parser (e.g. CREATE TABLE) or
- from old (before 10.2.1) frm.
-
- We have to create a new Virtual_column_info as for alter table,
- the current one may be shared with the original table.
- */
- Virtual_column_info *new_vcol= new (thd->mem_root) Virtual_column_info();
- LEX_STRING to;
- if (thd->copy_with_error(&my_charset_utf8mb4_general_ci,
- &to,
- thd->variables.character_set_client,
- v_col->expr_str.str, v_col->expr_str.length))
- return 1;
- *new_vcol= *v_col;
- new_vcol->expr_str= to;
- new_vcol->utf8= 1;
- *v_col_ptr= new_vcol;
- v_col= new_vcol;
- }
-
- /*
- Sum up the length of the expression string, it's optional name
- and the header.
- */
- (*length)+= (FRM_VCOL_NEW_HEADER_SIZE + v_col->name.length +
- v_col->expr_str.length);
+ if (buf->reserve(FRM_VCOL_NEW_HEADER_SIZE + vcol->name.length))
+ return 1;
+
+ buf->q_append((char) type);
+ buf->q_append2b(field_nr);
+ size_t len_off= buf->length();
+ buf->q_append2b(0); // to be added later
+ buf->q_append((char)vcol->name.length);
+ buf->q_append(vcol->name.str, vcol->name.length);
+ size_t expr_start= buf->length();
+ vcol->print(buf);
+ size_t expr_len= buf->length() - expr_start;
+ if (expr_len >= 65536)
+ {
+ my_error(ER_EXPRESSION_IS_TOO_BIG, MYF(0), vcol_type_name(type));
+ return 1;
+ }
+ int2store(buf->ptr() + len_off, expr_len);
return 0;
}
-/*
- pack_expression
-
- The data is stored as:
- 1 byte type (0 virtual, 1 virtual stored, 2 def, 3 check)
- 2 bytes field_number
- 2 bytes length of expression
- 1 byte length of name
- name
- next bytes column expression (text data)
-*/
-
-static void pack_expression(uchar **buff, Virtual_column_info *vcol,
- uint offset, uint type)
+static bool pack_vcols(String *buf, List<Create_field> &create_fields,
+ List<Virtual_column_info> *check_constraint_list)
{
- (*buff)[0]= (uchar) type;
- int2store((*buff)+1, offset);
- /*
- expr_str.length < 64K as we have checked that the total size of the
- frm file is < 64K
- */
- int2store((*buff)+3, vcol->expr_str.length);
- (*buff)[5]= vcol->name.length;
- (*buff)+= FRM_VCOL_NEW_HEADER_SIZE;
- memcpy((*buff), vcol->name.str, vcol->name.length);
- (*buff)+= vcol->name.length;
- memcpy((*buff), vcol->expr_str.str, vcol->expr_str.length);
- (*buff)+= vcol->expr_str.length;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
+
+ for (uint field_nr=0; (field= it++); field_nr++)
+ {
+ if (field->vcol_info)
+ if (pack_expression(buf, field->vcol_info, field_nr,
+ field->vcol_info->stored_in_db
+ ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL))
+ return 1;
+ if (field->has_default_expression() && !field->has_default_now_unireg_check())
+ if (pack_expression(buf, field->default_value, field_nr, VCOL_DEFAULT))
+ return 1;
+ if (field->check_constraint)
+ if (pack_expression(buf, field->check_constraint, field_nr,
+ VCOL_CHECK_FIELD))
+ return 1;
+ }
+
+ List_iterator<Virtual_column_info> cit(*check_constraint_list);
+ Virtual_column_info *check;
+ while ((check= cit++))
+ if (pack_expression(buf, check, UINT_MAX32, VCOL_CHECK_TABLE))
+ return 1;
+ return 0;
}
@@ -592,10 +591,10 @@ static bool pack_header(THD *thd, uchar *forminfo,
HA_CREATE_INFO *create_info, ulong data_offset,
handler *file)
{
- uint length,int_count,int_length, int_parts;
+ uint int_count,int_length, int_parts;
uint time_stamp_pos,null_fields;
uint table_options= create_info->table_options;
- size_t reclength, totlength, n_length, com_length, expression_length;
+ size_t length, reclength, totlength, n_length, com_length;
DBUG_ENTER("pack_header");
if (create_fields.elements > MAX_FIELDS)
@@ -611,16 +610,6 @@ static bool pack_header(THD *thd, uchar *forminfo,
n_length=2L;
create_info->field_check_constraints= 0;
- if (create_info->check_constraint_list->elements)
- {
- expression_length= packed_constraints_length(thd, create_info,
- create_info->check_constraint_list);
- if (!expression_length)
- DBUG_RETURN(1); // Wrong characterset
- }
- else
- expression_length= 0;
-
/* Check fields */
List_iterator<Create_field> it(create_fields);
Create_field *field;
@@ -630,14 +619,6 @@ static bool pack_header(THD *thd, uchar *forminfo,
ER_TOO_LONG_FIELD_COMMENT, field->field_name))
DBUG_RETURN(1);
- if (add_expr_length(thd, &field->vcol_info, &expression_length))
- DBUG_RETURN(1);
- if (field->default_value && field->default_value->expr_str.length)
- if (add_expr_length(thd, &field->default_value, &expression_length))
- DBUG_RETURN(1);
- if (add_expr_length(thd, &field->check_constraint, &expression_length))
- DBUG_RETURN(1);
-
totlength+= field->length;
com_length+= field->comment.length;
/*
@@ -714,31 +695,22 @@ static bool pack_header(THD *thd, uchar *forminfo,
DBUG_RETURN(1);
}
- if (expression_length)
- {
- expression_length+= FRM_VCOL_NEW_BASE_SIZE;
- create_info->expression_length= expression_length;
- }
-
/* Hack to avoid bugs with small static rows in MySQL */
- reclength=MY_MAX(file->min_record_length(table_options),reclength);
- if ((ulong) create_fields.elements*FCOMP+FRM_FORMINFO_SIZE+
- n_length+int_length+com_length+expression_length > 65535L ||
- int_count > 255)
+ reclength= MY_MAX(file->min_record_length(table_options), reclength);
+ length= n_length + create_fields.elements*FCOMP + FRM_FORMINFO_SIZE +
+ int_length + com_length + create_info->expression_length;
+ if (length > 65535L || int_count > 255)
{
my_message(ER_TOO_MANY_FIELDS, "Table definition is too large", MYF(0));
DBUG_RETURN(1);
}
bzero((char*)forminfo,FRM_FORMINFO_SIZE);
- length=(create_fields.elements*FCOMP+FRM_FORMINFO_SIZE+n_length+int_length+
- com_length+expression_length);
int2store(forminfo,length);
- forminfo[256] = 0;
int2store(forminfo+258,create_fields.elements);
- int2store(forminfo+260,0); // Screen length, not used anymore
+ // bytes 260-261 are unused
int2store(forminfo+262,totlength);
- int2store(forminfo+264,0); // unused
+ // bytes 264-265 are unused
int2store(forminfo+266,reclength);
int2store(forminfo+268,n_length);
int2store(forminfo+270,int_count);
@@ -749,7 +721,7 @@ static bool pack_header(THD *thd, uchar *forminfo,
int2store(forminfo+280,22); /* Rows needed */
int2store(forminfo+282,null_fields);
int2store(forminfo+284,com_length);
- int2store(forminfo+286,expression_length);
+ int2store(forminfo+286,create_info->expression_length);
DBUG_RETURN(0);
} /* pack_header */
@@ -811,29 +783,6 @@ static size_t packed_fields_length(List<Create_field> &create_fields)
DBUG_RETURN(length);
}
-
-static size_t packed_constraints_length(THD *thd, HA_CREATE_INFO *info,
- List<Virtual_column_info> *constr)
-{
- List_iterator<Virtual_column_info> it(*constr);
- size_t length= 0;
- Virtual_column_info *check;
-
- while ((check= it++))
- if (add_expr_length(thd, it.ref(), &length))
- return 0;
- return length;
-}
-
-static void pack_constraints(uchar **buff, List<Virtual_column_info> *constr)
-{
- List_iterator<Virtual_column_info> it(*constr);
- Virtual_column_info *check;
- while ((check= it++))
- pack_expression(buff, check, UINT_MAX32, 4);
-}
-
-
/* Save fields, fieldnames and intervals */
static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
@@ -959,27 +908,6 @@ static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
buff+= field->comment.length;
}
}
-
- if (create_info->expression_length)
- {
- /* Store header for packed fields (extra space for future) */
- bzero(buff, FRM_VCOL_NEW_BASE_SIZE);
- buff+= FRM_VCOL_NEW_BASE_SIZE;
-
- /* Store expressions */
- it.rewind();
- for (uint field_nr=0 ; (field= it++) ; field_nr++)
- {
- if (field->vcol_info)
- pack_expression(&buff, field->vcol_info, field_nr,
- field->vcol_info->stored_in_db ? 1 : 0);
- if (field->default_value && field->default_value->expr_str.length)
- pack_expression(&buff, field->default_value, field_nr, 2);
- if (field->check_constraint)
- pack_expression(&buff, field->check_constraint, field_nr, 3);
- }
- pack_constraints(&buff, create_info->check_constraint_list);
- }
*buff_arg= buff;
DBUG_RETURN(0);
}
@@ -1028,12 +956,9 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
field->sql_type,
field->charset,
field->geom_type, field->srid,
- 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->interval,
+ field->unireg_check,
+ field->save_interval ? field->save_interval
+ : field->interval,
field->field_name);
if (!regfield)
{
@@ -1053,9 +978,14 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
if (field->sql_type == MYSQL_TYPE_BIT && !f_bit_as_char(field->pack_flag))
null_count+= field->length & 7;
- if (field->default_value && !field->has_default_expression())
+ if (field->default_value && !field->default_value->flags &&
+ !(field->flags & BLOB_FLAG))
{
- int res= field->default_value->expr_item->save_in_field(regfield, 1);
+ Item *expr= field->default_value->expr_item;
+ int res= !expr->fixed && // may be already fixed if ALTER TABLE
+ expr->fix_fields(thd, &expr);
+ if (!res)
+ res= expr->save_in_field(regfield, 1);
/* If not ok or warning of level 'note' */
if (res != 0 && res != 3)
{