diff options
Diffstat (limited to 'sql/unireg.cc')
-rw-r--r-- | sql/unireg.cc | 217 |
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) { |