summaryrefslogtreecommitdiff
path: root/sql/unireg.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/unireg.cc')
-rw-r--r--sql/unireg.cc217
1 files changed, 137 insertions, 80 deletions
diff --git a/sql/unireg.cc b/sql/unireg.cc
index f565fc97d86..c99266dbff1 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -40,10 +40,12 @@
#define ALLOCA_THRESHOLD 2048
static uint pack_keys(uchar *,uint, KEY *, ulong);
-static bool pack_header(THD *, uchar *, List<Create_field> &, uint, ulong, handler *);
+static bool pack_header(THD *, uchar *, List<Create_field> &, HA_CREATE_INFO *info, ulong, handler *);
static uint get_interval_id(uint *,List<Create_field> &, Create_field *);
-static bool pack_fields(uchar *, List<Create_field> &, ulong);
+static bool pack_fields(uchar **, List<Create_field> &, 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(List<Virtual_column_info> *constr);
static bool make_empty_rec(THD *, uchar *, uint, List<Create_field> &, uint, ulong);
/*
@@ -106,7 +108,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
LEX_STRING str_db_type;
uint reclength, key_info_length, i;
ulong key_buff_length;
- ulong filepos, data_offset;
+ ulong filepos, data_offset, expr_length;
uint options_len;
uint gis_extra2_len= 0;
uchar fileinfo[FRM_HEADER_SIZE],forminfo[FRM_FORMINFO_SIZE];
@@ -121,13 +123,19 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
create_info->null_bits++;
data_offset= (create_info->null_bits + 7) / 8;
- error= pack_header(thd, forminfo, create_fields, create_info->table_options,
+ error= pack_header(thd, forminfo, create_fields, create_info,
data_offset, db_file);
if (error)
DBUG_RETURN(frm);
- reclength=uint2korr(forminfo+266);
+ reclength= uint2korr(forminfo+266);
+ expr_length= packed_constraints_length(create_info->constraint_list);
+
+ /* Correct expression length stored by pack_header */
+ expr_length+= uint2korr(forminfo+286);
+ int2store(forminfo+286, expr_length);
+ create_info->expression_lengths= expr_length;
/* Calculate extra data segment length */
str_db_type= *hton_name(create_info->db_type);
@@ -219,8 +227,9 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
filepos= frm.length;
frm.length+= FRM_FORMINFO_SIZE; // forminfo
frm.length+= packed_fields_length(create_fields);
+ frm.length+= expr_length;
- if (frm.length > FRM_MAX_SIZE)
+ if (frm.length > FRM_MAX_SIZE || expr_length > UINT_MAX32)
{
my_error(ER_TABLE_DEFINITION_TOO_BIG, MYF(0), table);
DBUG_RETURN(frm);
@@ -326,8 +335,10 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table,
}
memcpy(frm_ptr + filepos, forminfo, 288);
- if (pack_fields(frm_ptr + filepos + 288, create_fields, data_offset))
+ pos= frm_ptr + filepos + 288;
+ if (pack_fields(&pos, create_fields, data_offset))
goto err;
+ pack_constraints(&pos, create_info->constraint_list);
{
/*
@@ -488,15 +499,73 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
} /* pack_keys */
+/**
+ Calculate and check length of stored expression (virtual, def, check)
+
+ @param v_col Virtual expression. Can be 0
+ @param length Sum total lengths here
+
+ Note to make calls easier, one can call this with v_col == 0
+*/
+
+static void add_expr_length(Virtual_column_info *v_col, size_t *length)
+{
+ if (!v_col)
+ return;
+ /*
+ 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);
+ return;
+}
+
+
+/*
+ pack_expression
+
+ The data is stored as:
+ 2 bytes field_number
+ 2 bytes length of expression
+ 1 byte type (0 virtual, 1 virtual stored, 2 def, 3 check)
+ 1 byte length of name
+ 1 byte flags; 1 = non deterministic expression
+ name
+ next bytes column expression (text data)
+*/
+
+static void pack_expression(uchar **buff, Virtual_column_info *vcol,
+ uint offset, uint type)
+{
+ int2store((*buff), offset);
+ /*
+ expr_str.length < 64K as we have checked that the total size of the
+ frm file is < 64K
+ */
+ int2store((*buff)+2, vcol->expr_str.length);
+ (*buff)[4]= (uchar) type;
+ (*buff)[5]= vcol->name.length;
+ (*buff)[6]= vcol->non_deterministic; // 1 bit used for now
+ (*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;
+}
+
+
/* Make formheader */
static bool pack_header(THD *thd, uchar *forminfo,
List<Create_field> &create_fields,
- uint table_options, ulong data_offset, handler *file)
+ HA_CREATE_INFO *create_info, ulong data_offset,
+ handler *file)
{
uint length,int_count,int_length,no_empty, int_parts;
uint time_stamp_pos,null_fields;
- ulong reclength, totlength, n_length, com_length, vcol_info_length;
+ uint table_options= create_info->table_options;
+ size_t reclength, totlength, n_length, com_length, expression_length;
DBUG_ENTER("pack_header");
if (create_fields.elements > MAX_FIELDS)
@@ -508,8 +577,9 @@ static bool pack_header(THD *thd, uchar *forminfo,
totlength= 0L;
reclength= data_offset;
no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=0;
- com_length=vcol_info_length=0;
+ com_length=expression_length=0;
n_length=2L;
+ create_info->field_check_constraints= 0;
/* Check fields */
List_iterator<Create_field> it(create_fields);
@@ -520,30 +590,10 @@ static bool pack_header(THD *thd, uchar *forminfo,
ER_TOO_LONG_FIELD_COMMENT, field->field_name))
DBUG_RETURN(1);
- if (field->vcol_info)
- {
- uint col_expr_maxlen= field->virtual_col_expr_maxlen();
- uint tmp_len= my_charpos(system_charset_info,
- field->vcol_info->expr_str.str,
- field->vcol_info->expr_str.str +
- field->vcol_info->expr_str.length,
- col_expr_maxlen);
-
- if (tmp_len < field->vcol_info->expr_str.length)
- {
- my_error(ER_WRONG_STRING_LENGTH, MYF(0),
- field->vcol_info->expr_str.str,"VIRTUAL COLUMN EXPRESSION",
- col_expr_maxlen);
- DBUG_RETURN(1);
- }
- /*
- Sum up the length of the expression string and the length of the
- mandatory header to the total length of info on the defining
- expressions saved in the frm file for virtual columns.
- */
- vcol_info_length+= field->vcol_info->expr_str.length+
- FRM_VCOL_HEADER_SIZE(field->interval);
- }
+ add_expr_length(field->vcol_info, &expression_length);
+ if (field->has_default_expression())
+ add_expr_length(field->default_value, &expression_length);
+ add_expr_length(field->check_constraint, &expression_length);
totlength+= field->length;
com_length+= field->comment.length;
@@ -616,6 +666,8 @@ static bool pack_header(THD *thd, uchar *forminfo,
}
if (f_maybe_null(field->pack_flag))
null_fields++;
+ if (field->check_constraint)
+ create_info->field_check_constraints++;
}
int_length+=int_count*2; // 255 prefix + 0 suffix
@@ -628,7 +680,7 @@ static bool pack_header(THD *thd, uchar *forminfo,
/* 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+vcol_info_length > 65535L ||
+ n_length+int_length+com_length+expression_length > 65535L ||
int_count > 255)
{
my_message(ER_TOO_MANY_FIELDS, ER_THD(thd, ER_TOO_MANY_FIELDS), MYF(0));
@@ -637,11 +689,11 @@ static bool pack_header(THD *thd, uchar *forminfo,
bzero((char*)forminfo,FRM_FORMINFO_SIZE);
length=(create_fields.elements*FCOMP+FRM_FORMINFO_SIZE+n_length+int_length+
- com_length+vcol_info_length);
+ com_length+expression_length);
int2store(forminfo,length);
forminfo[256] = 0;
int2store(forminfo+258,create_fields.elements);
- int2store(forminfo+260,0);
+ int2store(forminfo+260,0); // Screen length, not used anymore
int2store(forminfo+262,totlength);
int2store(forminfo+264,no_empty);
int2store(forminfo+266,reclength);
@@ -654,7 +706,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,vcol_info_length);
+ int2store(forminfo+286,expression_length);
DBUG_RETURN(0);
} /* pack_header */
@@ -707,11 +759,11 @@ static size_t packed_fields_length(List<Create_field> &create_fields)
}
length++;
}
- if (field->vcol_info)
- {
- length+= field->vcol_info->expr_str.length +
- FRM_VCOL_HEADER_SIZE(field->interval);
- }
+
+ add_expr_length(field->vcol_info, &length);
+ if (field->has_default_expression())
+ add_expr_length(field->default_value, &length);
+ add_expr_length(field->check_constraint, &length);
length+= FCOMP;
length+= strlen(field->field_name)+1;
length+= field->comment.length;
@@ -721,12 +773,34 @@ static size_t packed_fields_length(List<Create_field> &create_fields)
DBUG_RETURN(length);
}
+
+static size_t packed_constraints_length(List<Virtual_column_info> *constr)
+{
+ List_iterator<Virtual_column_info> it(*constr);
+ size_t length= 0;
+ Virtual_column_info *check;
+ while ((check= it++))
+ add_expr_length(check, &length);
+ 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, List<Create_field> &create_fields,
+static bool pack_fields(uchar **buff_arg, List<Create_field> &create_fields,
ulong data_offset)
{
- uint int_count, comment_length= 0, vcol_info_length=0;
+ uchar *buff= *buff_arg;
+ uint int_count, comment_length= 0;
+ bool has_expressions= 0;
Create_field *field;
DBUG_ENTER("pack_fields");
@@ -736,7 +810,6 @@ static bool pack_fields(uchar *buff, List<Create_field> &create_fields,
while ((field=it++))
{
uint recpos;
- uint cur_vcol_expr_len= 0;
int2store(buff+3, field->length);
/* The +1 is here becasue the col offset in .frm file have offset 1 */
recpos= field->offset+1 + (uint) data_offset;
@@ -763,17 +836,10 @@ static bool pack_fields(uchar *buff, List<Create_field> &create_fields,
{
buff[11]= buff[14]= 0; // Numerical
}
- if (field->vcol_info)
- {
- /*
- Use the interval_id place in the .frm file to store the length of
- the additional data saved for the virtual field
- */
- buff[12]= cur_vcol_expr_len= field->vcol_info->expr_str.length +
- FRM_VCOL_HEADER_SIZE(field->interval);
- vcol_info_length+= cur_vcol_expr_len;
- buff[13]= (uchar) MYSQL_TYPE_VIRTUAL;
- }
+ if (field->vcol_info || field->has_default_expression() ||
+ field->check_constraint)
+ has_expressions= 1;
+
int2store(buff+15, field->comment.length);
comment_length+= field->comment.length;
set_if_bigger(int_count,field->interval_id);
@@ -857,35 +923,26 @@ static bool pack_fields(uchar *buff, List<Create_field> &create_fields,
buff+= field->comment.length;
}
}
- if (vcol_info_length)
+
+ if (has_expressions)
{
+ /* Store expressions */
it.rewind();
- while ((field=it++))
+ for (uint field_nr=0 ; (field= it++) ; field_nr++)
{
- /*
- Pack each virtual field as follows:
- byte 1 = interval_id == 0 ? 1 : 2
- byte 2 = sql_type
- byte 3 = flags (as of now, 0 - no flags, 1 - field is physically stored)
- [byte 4] = possible interval_id for sql_type
- next byte ... = virtual column expression (text data)
- */
- if (field->vcol_info && field->vcol_info->expr_str.length)
- {
- *buff++= (uchar) (1 + MY_TEST(field->interval));
- *buff++= (uchar) field->sql_type;
- *buff++= (uchar) field->vcol_info->stored_in_db;
- if (field->interval)
- *buff++= (uchar) field->interval_id;
- memcpy(buff, field->vcol_info->expr_str.str, field->vcol_info->expr_str.length);
- buff+= field->vcol_info->expr_str.length;
- }
+ if (field->vcol_info)
+ pack_expression(&buff, field->vcol_info, field_nr,
+ field->vcol_info->stored_in_db ? 1 : 0);
+ if (field->has_default_expression())
+ pack_expression(&buff, field->default_value, field_nr, 2);
+ if (field->check_constraint)
+ pack_expression(&buff, field->check_constraint, field_nr, 3);
}
}
+ *buff_arg= buff;
DBUG_RETURN(0);
}
-
/* save an empty record on start of formfile */
static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
@@ -955,9 +1012,9 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
type= (Field::utype) MTYP_TYPENR(field->unireg_check);
- if (field->def)
+ if (field->default_value && !field->has_default_expression())
{
- int res= field->def->save_in_field(regfield, 1);
+ int res= field->default_value->expr_item->save_in_field(regfield, 1);
/* If not ok or warning of level 'note' */
if (res != 0 && res != 3)
{