MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
unireg.cc
1 /*
2  Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 /*
19  Functions to create a unireg form-file from a FIELD and a fieldname-fieldinfo
20  struct.
21  In the following functions FIELD * is an ordinary field-structure with
22  the following exeptions:
23  sc_length,typepos,row,kol,dtype,regnr and field need not to be set.
24  str is a (long) to record position where 0 is the first position.
25 */
26 
27 #include "sql_priv.h"
28 #include "unireg.h"
29 #include "sql_partition.h" // struct partition_info
30 #include "sql_table.h" // validate_comment_length
31 #include "sql_class.h" // THD, Internal_error_handler
32 #include <m_ctype.h>
33 #include <assert.h>
34 
35 #include <algorithm>
36 
37 using std::min;
38 using std::max;
39 
40 #define FCOMP 17 /* Bytes for a packed field */
41 
42 static uchar * pack_screens(List<Create_field> &create_fields,
43  uint *info_length, uint *screens, bool small_file);
44 static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
45  ulong data_offset);
46 static bool pack_header(uchar *forminfo,enum legacy_db_type table_type,
47  List<Create_field> &create_fields,
48  uint info_length, uint screens, uint table_options,
49  ulong data_offset, handler *file);
50 static uint get_interval_id(uint *,List<Create_field> &, Create_field *);
51 static bool pack_fields(File file, List<Create_field> &create_fields,
52  ulong data_offset);
53 static bool make_empty_rec(THD *thd, int file,
54  uint table_options,
55  List<Create_field> &create_fields,
56  uint reclength, ulong data_offset,
57  handler *handler);
65 struct Pack_header_error_handler: public Internal_error_handler
66 {
67  virtual bool handle_condition(THD *thd,
68  uint sql_errno,
69  const char* sqlstate,
70  Sql_condition::enum_warning_level level,
71  const char* msg,
72  Sql_condition ** cond_hdl);
73  bool is_handled;
74  Pack_header_error_handler() :is_handled(FALSE) {}
75 };
76 
77 
78 bool
79 Pack_header_error_handler::
80 handle_condition(THD *,
81  uint sql_errno,
82  const char*,
83  Sql_condition::enum_warning_level,
84  const char*,
85  Sql_condition ** cond_hdl)
86 {
87  *cond_hdl= NULL;
88  is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
89  return is_handled;
90 }
91 
92 /*
93  Create a frm (table definition) file
94 
95  SYNOPSIS
96  mysql_create_frm()
97  thd Thread handler
98  file_name Path for file (including database and .frm)
99  db Name of database
100  table Name of table
101  create_info create info parameters
102  create_fields Fields to create
103  keys number of keys to create
104  key_info Keys to create
105  db_file Handler to use. May be zero, in which case we use
106  create_info->db_type
107  RETURN
108  false ok
109  true error
110 */
111 
112 bool mysql_create_frm(THD *thd, const char *file_name,
113  const char *db, const char *table,
114  HA_CREATE_INFO *create_info,
115  List<Create_field> &create_fields,
116  uint keys, KEY *key_info,
117  handler *db_file)
118 {
119  LEX_STRING str_db_type;
120  uint reclength, info_length, screens, key_info_length, maxlength, i;
121  ulong key_buff_length;
122  File file;
123  ulong filepos, data_offset;
124  uchar fileinfo[64],forminfo[288],*keybuff, *forminfo_p= forminfo;
125  uchar *screen_buff= NULL;
126  char buff[128];
127 #ifdef WITH_PARTITION_STORAGE_ENGINE
128  partition_info *part_info= thd->work_part_info;
129 #endif
130  Pack_header_error_handler pack_header_error_handler;
131  int error;
132  const uint format_section_header_size= 8;
133  uint format_section_length;
134  uint tablespace_length= 0;
135  DBUG_ENTER("mysql_create_frm");
136 
137  DBUG_ASSERT(*fn_rext((char*)file_name)); // Check .frm extension
138 
139  if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
140  DBUG_RETURN(1);
141  DBUG_ASSERT(db_file != NULL);
142 
143  /* If fixed row records, we need one bit to check for deleted rows */
144  if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
145  create_info->null_bits++;
146  data_offset= (create_info->null_bits + 7) / 8;
147 
148  thd->push_internal_handler(&pack_header_error_handler);
149 
150  error= pack_header(forminfo, ha_legacy_type(create_info->db_type),
151  create_fields,info_length,
152  screens, create_info->table_options,
153  data_offset, db_file);
154 
155  thd->pop_internal_handler();
156 
157  if (error)
158  {
159  my_free(screen_buff);
160  if (! pack_header_error_handler.is_handled)
161  DBUG_RETURN(1);
162 
163  // Try again without UNIREG screens (to get more columns)
164  if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
165  DBUG_RETURN(1);
166  if (pack_header(forminfo, ha_legacy_type(create_info->db_type),
167  create_fields,info_length,
168  screens, create_info->table_options, data_offset, db_file))
169  {
170  my_free(screen_buff);
171  DBUG_RETURN(1);
172  }
173  }
174  reclength=uint2korr(forminfo+266);
175 
176  /* Calculate extra data segment length */
177  str_db_type.str= (char *) ha_resolve_storage_engine_name(create_info->db_type);
178  str_db_type.length= strlen(str_db_type.str);
179  /* str_db_type */
180  create_info->extra_size= (2 + str_db_type.length +
181  2 + create_info->connect_string.length);
182  /*
183  Partition:
184  Length of partition info = 4 byte
185  Potential NULL byte at end of partition info string = 1 byte
186  Indicator if auto-partitioned table = 1 byte
187  => Total 6 byte
188  */
189  create_info->extra_size+= 6;
190 #ifdef WITH_PARTITION_STORAGE_ENGINE
191  if (part_info)
192  {
193  create_info->extra_size+= part_info->part_info_len;
194  }
195 #endif
196 
197  for (i= 0; i < keys; i++)
198  {
199  if (key_info[i].parser_name)
200  create_info->extra_size+= key_info[i].parser_name->length + 1;
201  }
202  /*
203  This gives us the byte-position of the character at
204  (character-position, not byte-position) TABLE_COMMENT_MAXLEN.
205  The trick here is that character-positions start at 0, so the last
206  character in a maximum-allowed length string would be at char-pos
207  MAXLEN-1; charpos MAXLEN will be the position of the terminator.
208  Consequently, bytepos(charpos(MAXLEN)) should be equal to
209  comment[length] (which should also be the terminator, or at least
210  the first byte after the payload in the strict sense). If this is
211  not so (bytepos(charpos(MAXLEN)) comes /before/ the end of the
212  string), the string is too long.
213 
214  For additional credit, realise that UTF-8 has 1-3 bytes before 6.0,
215  and 1-4 bytes in 6.0 (6.0 also has UTF-32).
216  */
217  if (create_info->comment.length > TABLE_COMMENT_MAXLEN)
218  {
219  const char *real_table_name= table;
220  List_iterator<Create_field> it(create_fields);
221  Create_field *field;
222  while ((field=it++))
223  {
224  if (field->field && field->field->table &&
225  (real_table_name= field->field->table->s->table_name.str))
226  break;
227  }
228  if (validate_comment_length(thd,
229  create_info->comment.str,
230  &create_info->comment.length,
231  TABLE_COMMENT_MAXLEN,
232  ER_TOO_LONG_TABLE_COMMENT,
233  real_table_name))
234  {
235  my_free(screen_buff);
236  DBUG_RETURN(true);
237  }
238  }
239  /*
240  If table comment is longer than TABLE_COMMENT_INLINE_MAXLEN bytes,
241  store the comment in an extra segment (up to TABLE_COMMENT_MAXLEN bytes).
242  Pre 6.0, the limit was 60 characters, with no extra segment-handling.
243  */
244  if (create_info->comment.length > TABLE_COMMENT_INLINE_MAXLEN)
245  {
246  forminfo[46]=255;
247  create_info->extra_size+= 2 + create_info->comment.length;
248  }
249  else{
250  strmake((char*) forminfo+47, create_info->comment.str ?
251  create_info->comment.str : "", create_info->comment.length);
252  forminfo[46]=(uchar) create_info->comment.length;
253  }
254 
255  /*
256  Add room in extra segment for "format section" with additional
257  table and column properties
258  */
259  if (create_info->tablespace)
260  tablespace_length= strlen(create_info->tablespace);
261  format_section_length=
262  format_section_header_size +
263  tablespace_length + 1 +
264  create_fields.elements;
265  create_info->extra_size+= format_section_length;
266 
267  if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
268  create_info, keys, key_info)) < 0)
269  {
270  my_free(screen_buff);
271  DBUG_RETURN(1);
272  }
273 
274  key_buff_length= uint4korr(fileinfo+47);
275  keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
276  key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
277 
278  /*
279  Ensure that there are no forms in this newly created form file.
280  Even if the form file exists, create_frm must truncate it to
281  ensure one form per form file.
282  */
283  DBUG_ASSERT(uint2korr(fileinfo+8) == 0);
284 
285  if (!(filepos= make_new_entry(file, fileinfo, NULL, "")))
286  goto err;
287  maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo_p)+1000));
288  int2store(forminfo+2,maxlength);
289  int4store(fileinfo+10,(ulong) (filepos+maxlength));
290  fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
291  (create_info->min_rows == 1) && (keys == 0));
292  int2store(fileinfo+28,key_info_length);
293 
294 #ifdef WITH_PARTITION_STORAGE_ENGINE
295  if (part_info)
296  {
297  fileinfo[61]= (uchar) ha_legacy_type(part_info->default_engine_type);
298  DBUG_PRINT("info", ("part_db_type = %d", fileinfo[61]));
299  }
300 #endif
301  int2store(fileinfo+59,db_file->extra_rec_buf_length());
302 
303  if (mysql_file_pwrite(file, fileinfo, 64, 0L, MYF_RW) ||
304  mysql_file_pwrite(file, keybuff, key_info_length,
305  (ulong) uint2korr(fileinfo+6), MYF_RW))
306  goto err;
307  mysql_file_seek(file,
308  (ulong) uint2korr(fileinfo+6) + (ulong) key_buff_length,
309  MY_SEEK_SET, MYF(0));
310  if (make_empty_rec(thd,file,
311  create_info->table_options,
312  create_fields,reclength, data_offset, db_file))
313  goto err;
314 
315  int2store(buff, create_info->connect_string.length);
316  if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
317  mysql_file_write(file, (const uchar*)create_info->connect_string.str,
318  create_info->connect_string.length, MYF(MY_NABP)))
319  goto err;
320 
321  int2store(buff, str_db_type.length);
322  if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
323  mysql_file_write(file, (const uchar*)str_db_type.str,
324  str_db_type.length, MYF(MY_NABP)))
325  goto err;
326 
327 #ifdef WITH_PARTITION_STORAGE_ENGINE
328  if (part_info)
329  {
330  char auto_partitioned= part_info->is_auto_partitioned ? 1 : 0;
331  int4store(buff, part_info->part_info_len);
332  if (mysql_file_write(file, (const uchar*)buff, 4, MYF_RW) ||
333  mysql_file_write(file, (const uchar*)part_info->part_info_string,
334  part_info->part_info_len + 1, MYF_RW) ||
335  mysql_file_write(file, (const uchar*)&auto_partitioned, 1, MYF_RW))
336  goto err;
337  }
338  else
339 #endif
340  {
341  memset(buff, 0, 6);
342  if (mysql_file_write(file, (uchar*) buff, 6, MYF_RW))
343  goto err;
344  }
345  for (i= 0; i < keys; i++)
346  {
347  if (key_info[i].parser_name)
348  {
349  if (mysql_file_write(file, (const uchar*)key_info[i].parser_name->str,
350  key_info[i].parser_name->length + 1, MYF(MY_NABP)))
351  goto err;
352  }
353  }
354  if (forminfo[46] == (uchar)255)
355  {
356  uchar comment_length_buff[2];
357  int2store(comment_length_buff,create_info->comment.length);
358  if (mysql_file_write(file, comment_length_buff, 2, MYF(MY_NABP)) ||
359  mysql_file_write(file, (uchar*) create_info->comment.str,
360  create_info->comment.length, MYF(MY_NABP)))
361  goto err;
362  }
363 
364  /* "Format section" with additional table and column properties */
365  {
366  uchar *ptr, *format_section_buff;
367  if (!(format_section_buff=(uchar*) my_malloc(format_section_length,
368  MYF(MY_WME))))
369  goto err;
370  ptr= format_section_buff;
371 
372  /* header */
373  const uint format_section_flags=
374  create_info->storage_media; // 3 bits
375  const uint format_section_unused= 0;
376  int2store(ptr+0, format_section_length);
377  int4store(ptr+2, format_section_flags);
378  int2store(ptr+6, format_section_unused);
379  ptr+= format_section_header_size;
380 
381  /* tablespace name */
382  if (tablespace_length > 0)
383  memcpy(ptr, create_info->tablespace, tablespace_length);
384  ptr+= tablespace_length;
385  *ptr= 0; /* tablespace string terminating zero */
386  ptr++;
387 
388  /* column properties */
389  Create_field *field;
390  List_iterator<Create_field> it(create_fields);
391  while ((field=it++))
392  {
393  const uchar field_storage= field->field_storage_type();
394  const uchar field_column_format= field->column_format();
395  const uchar field_flags=
396  field_storage + (field_column_format << COLUMN_FORMAT_SHIFT);
397  *ptr= field_flags;
398  ptr++;
399  }
400  DBUG_ASSERT(format_section_buff + format_section_length == ptr);
401 
402  if (mysql_file_write(file, format_section_buff,
403  format_section_length, MYF_RW))
404  {
405  my_free(format_section_buff);
406  goto err;
407  }
408  DBUG_PRINT("info", ("wrote format section, length: %u",
409  format_section_length));
410  my_free(format_section_buff);
411  }
412 
413  mysql_file_seek(file, filepos, MY_SEEK_SET, MYF(0));
414  if (mysql_file_write(file, forminfo, 288, MYF_RW) ||
415  mysql_file_write(file, screen_buff, info_length, MYF_RW) ||
416  pack_fields(file, create_fields, data_offset))
417  goto err;
418 
419 #ifdef HAVE_CRYPTED_FRM
420  if (create_info->password)
421  {
422  char tmp=2,*disk_buff=0;
423  SQL_CRYPT *crypted=new SQL_CRYPT(create_info->password);
424  if (!crypted || mysql_file_pwrite(file, &tmp, 1, 26, MYF_RW))// Mark crypted
425  goto err;
426  uint read_length=uint2korr(forminfo)-256;
427  mysql_file_seek(file, filepos+256, MY_SEEK_SET, MYF(0));
428  if (read_string(file,(uchar**) &disk_buff,read_length))
429  goto err;
430  crypted->encode(disk_buff,read_length);
431  delete crypted;
432  if (mysql_file_pwrite(file, disk_buff, read_length, filepos+256, MYF_RW))
433  {
434  my_free(disk_buff);
435  goto err;
436  }
437  my_free(disk_buff);
438  }
439 #endif
440 
441  my_free(screen_buff);
442  my_free(keybuff);
443 
444  if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
445  (mysql_file_sync(file, MYF(MY_WME)) ||
446  my_sync_dir_by_file(file_name, MYF(MY_WME))))
447  goto err2;
448 
449  if (mysql_file_close(file, MYF(MY_WME)))
450  goto err3;
451 
452  {
453  /*
454  Restore all UCS2 intervals.
455  HEX representation of them is not needed anymore.
456  */
457  List_iterator<Create_field> it(create_fields);
458  Create_field *field;
459  while ((field=it++))
460  {
461  if (field->save_interval)
462  {
463  field->interval= field->save_interval;
464  field->save_interval= 0;
465  }
466  }
467  }
468  DBUG_RETURN(0);
469 
470 err:
471  my_free(screen_buff);
472  my_free(keybuff);
473 err2:
474  (void) mysql_file_close(file, MYF(MY_WME));
475 err3:
476  mysql_file_delete(key_file_frm, file_name, MYF(0));
477  DBUG_RETURN(1);
478 } /* mysql_create_frm */
479 
480 
501 int rea_create_table(THD *thd, const char *path,
502  const char *db, const char *table_name,
503  HA_CREATE_INFO *create_info,
504  List<Create_field> &create_fields,
505  uint keys, KEY *key_info, handler *file,
506  bool no_ha_table)
507 {
508  DBUG_ENTER("rea_create_table");
509 
510  char frm_name[FN_REFLEN];
511  strxmov(frm_name, path, reg_ext, NullS);
512  if (mysql_create_frm(thd, frm_name, db, table_name, create_info,
513  create_fields, keys, key_info, file))
514 
515  DBUG_RETURN(1);
516 
517  // Make sure mysql_create_frm din't remove extension
518  DBUG_ASSERT(*fn_rext(frm_name));
519  if (thd->variables.keep_files_on_create)
520  create_info->options|= HA_CREATE_KEEP_FILES;
521 
522  if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG,
523  create_info))
524  goto err_handler_frm;
525 
526  if (!no_ha_table &&
527  ha_create_table(thd, path, db, table_name, create_info, 0))
528  goto err_handler;
529  DBUG_RETURN(0);
530 
531 err_handler:
532  (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
533 
534 err_handler_frm:
535  mysql_file_delete(key_file_frm, frm_name, MYF(0));
536  DBUG_RETURN(1);
537 } /* rea_create_table */
538 
539 
540  /* Pack screens to a screen for save in a form-file */
541 
542 static uchar *pack_screens(List<Create_field> &create_fields,
543  uint *info_length, uint *screens,
544  bool small_file)
545 {
546  reg1 uint i;
547  uint row,start_row,end_row,fields_on_screen;
548  uint length,cols;
549  uchar *info,*pos,*start_screen;
550  uint fields=create_fields.elements;
551  List_iterator<Create_field> it(create_fields);
552  DBUG_ENTER("pack_screens");
553 
554  start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;
555 
556  *screens=(fields-1)/fields_on_screen+1;
557  length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);
558 
559  Create_field *field;
560  while ((field=it++))
561  length+=(uint) strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
562 
563  if (!(info=(uchar*) my_malloc(length,MYF(MY_WME))))
564  DBUG_RETURN(0);
565 
566  start_screen=0;
567  row=end_row;
568  pos=info;
569  it.rewind();
570  for (i=0 ; i < fields ; i++)
571  {
572  Create_field *cfield=it++;
573  if (row++ == end_row)
574  {
575  if (i)
576  {
577  length=(uint) (pos-start_screen);
578  int2store(start_screen,length);
579  start_screen[2]=(uchar) (fields_on_screen+1);
580  start_screen[3]=(uchar) (fields_on_screen);
581  }
582  row=start_row;
583  start_screen=pos;
584  pos+=4;
585  pos[0]= (uchar) start_row-2; /* Header string */
586  pos[1]= (uchar) (cols >> 2);
587  pos[2]= (uchar) (cols >> 1) +1;
588  strfill((char *) pos+3,(uint) (cols >> 1),' ');
589  pos+=(cols >> 1)+4;
590  }
591  length=(uint) strlen(cfield->field_name);
592  if (length > cols-3)
593  length=cols-3;
594 
595  if (!small_file)
596  {
597  pos[0]=(uchar) row;
598  pos[1]=0;
599  pos[2]=(uchar) (length+1);
600  pos=(uchar*) strmake((char*) pos+3,cfield->field_name,length)+1;
601  }
602  cfield->row=(uint8) row;
603  cfield->col=(uint8) (length+1);
604  cfield->sc_length= min<uint8>(cfield->length, cols - (length + 2));
605  }
606  length=(uint) (pos-start_screen);
607  int2store(start_screen,length);
608  start_screen[2]=(uchar) (row-start_row+2);
609  start_screen[3]=(uchar) (row-start_row+1);
610 
611  *info_length=(uint) (pos-info);
612  DBUG_RETURN(info);
613 } /* pack_screens */
614 
615 
616  /* Pack keyinfo and keynames to keybuff for save in form-file. */
617 
618 static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
619  ulong data_offset)
620 {
621  uint key_parts,length;
622  uchar *pos, *keyname_pos;
623  KEY *key,*end;
624  KEY_PART_INFO *key_part,*key_part_end;
625  DBUG_ENTER("pack_keys");
626 
627  pos=keybuff+6;
628  key_parts=0;
629  for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
630  {
631  int2store(pos, (key->flags ^ HA_NOSAME));
632  int2store(pos+2,key->key_length);
633  pos[4]= (uchar) key->user_defined_key_parts;
634  pos[5]= (uchar) key->algorithm;
635  int2store(pos+6, key->block_size);
636  pos+=8;
637  key_parts+=key->user_defined_key_parts;
638  DBUG_PRINT("loop", ("flags: %lu key_parts: %d at 0x%lx",
639  key->flags, key->user_defined_key_parts,
640  (long) key->key_part));
641  for (key_part=key->key_part,
642  key_part_end= key_part + key->user_defined_key_parts ;
643  key_part != key_part_end ;
644  key_part++)
645 
646  {
647  uint offset;
648  DBUG_PRINT("loop",("field: %d startpos: %lu length: %d",
649  key_part->fieldnr, key_part->offset + data_offset,
650  key_part->length));
651  int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
652  offset= (uint) (key_part->offset+data_offset+1);
653  int2store(pos+2, offset);
654  pos[4]=0; // Sort order
655  int2store(pos+5,key_part->key_type);
656  int2store(pos+7,key_part->length);
657  pos+=9;
658  }
659  }
660  /* Save keynames */
661  keyname_pos=pos;
662  *pos++=(uchar) NAMES_SEP_CHAR;
663  for (key=keyinfo ; key != end ; key++)
664  {
665  uchar *tmp=(uchar*) strmov((char*) pos,key->name);
666  *tmp++= (uchar) NAMES_SEP_CHAR;
667  *tmp=0;
668  pos=tmp;
669  }
670  *(pos++)=0;
671  for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
672  {
673  if (key->flags & HA_USES_COMMENT)
674  {
675  int2store(pos, key->comment.length);
676  uchar *tmp= (uchar*)strnmov((char*) pos+2,key->comment.str,
677  key->comment.length);
678  pos= tmp;
679  }
680  }
681 
682  if (key_count > 127 || key_parts > 127)
683  {
684  keybuff[0]= (key_count & 0x7f) | 0x80;
685  keybuff[1]= key_count >> 7;
686  int2store(keybuff+2,key_parts);
687  }
688  else
689  {
690  keybuff[0]=(uchar) key_count;
691  keybuff[1]=(uchar) key_parts;
692  keybuff[2]= keybuff[3]= 0;
693  }
694  length=(uint) (pos-keyname_pos);
695  int2store(keybuff+4,length);
696  DBUG_RETURN((uint) (pos-keybuff));
697 } /* pack_keys */
698 
699 
700  /* Make formheader */
701 
702 static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
703  List<Create_field> &create_fields,
704  uint info_length, uint screens, uint table_options,
705  ulong data_offset, handler *file)
706 {
707  uint length,int_count,int_length,no_empty, int_parts;
708  uint time_stamp_pos,null_fields;
709  ulong reclength, totlength, n_length, com_length;
710  DBUG_ENTER("pack_header");
711 
712  if (create_fields.elements > MAX_FIELDS)
713  {
714  my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
715  DBUG_RETURN(1);
716  }
717 
718  totlength= 0L;
719  reclength= data_offset;
720  no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=
721  com_length=0;
722  n_length=2L;
723 
724  /* Check fields */
725 
726  List_iterator<Create_field> it(create_fields);
727  Create_field *field;
728  while ((field=it++))
729  {
730  if (validate_comment_length(current_thd,
731  field->comment.str,
732  &field->comment.length,
733  COLUMN_COMMENT_MAXLEN,
734  ER_TOO_LONG_FIELD_COMMENT,
735  (char *) field->field_name))
736  DBUG_RETURN(true);
737  totlength+= field->length;
738  com_length+= field->comment.length;
739  if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY ||
740  field->unireg_check & MTYP_NOEMPTY_BIT)
741  {
742  field->unireg_check= (Field::utype) ((uint) field->unireg_check |
743  MTYP_NOEMPTY_BIT);
744  no_empty++;
745  }
746  /*
747  We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE
748  as auto-update field.
749  */
750  if (field->sql_type == MYSQL_TYPE_TIMESTAMP &&
751  MTYP_TYPENR(field->unireg_check) != Field::NONE &&
752  !time_stamp_pos)
753  time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
754  length=field->pack_length;
755  /* Ensure we don't have any bugs when generating offsets */
756  DBUG_ASSERT(reclength == field->offset + data_offset);
757  if ((uint) field->offset+ (uint) data_offset+ length > reclength)
758  reclength=(uint) (field->offset+ data_offset + length);
759  n_length+= (ulong) strlen(field->field_name)+1;
760  field->interval_id=0;
761  field->save_interval= 0;
762  if (field->interval)
763  {
764  uint old_int_count=int_count;
765 
766  if (field->charset->mbminlen > 1)
767  {
768  /*
769  Escape UCS2 intervals using HEX notation to avoid
770  problems with delimiters between enum elements.
771  As the original representation is still needed in
772  the function make_empty_rec to create a record of
773  filled with default values it is saved in save_interval
774  The HEX representation is created from this copy.
775  */
776  field->save_interval= field->interval;
777  field->interval= (TYPELIB*) sql_alloc(sizeof(TYPELIB));
778  *field->interval= *field->save_interval;
779  field->interval->type_names=
780  (const char **) sql_alloc(sizeof(char*) *
781  (field->interval->count+1));
782  field->interval->type_names[field->interval->count]= 0;
783  field->interval->type_lengths=
784  (uint *) sql_alloc(sizeof(uint) * field->interval->count);
785 
786  for (uint pos= 0; pos < field->interval->count; pos++)
787  {
788  char *dst;
789  const char *src= field->save_interval->type_names[pos];
790  uint hex_length;
791  length= field->save_interval->type_lengths[pos];
792  hex_length= length * 2;
793  field->interval->type_lengths[pos]= hex_length;
794  field->interval->type_names[pos]= dst= (char*) sql_alloc(hex_length +
795  1);
796  octet2hex(dst, src, length);
797  }
798  }
799 
800  field->interval_id=get_interval_id(&int_count,create_fields,field);
801  if (old_int_count != int_count)
802  {
803  for (const char **pos=field->interval->type_names ; *pos ; pos++)
804  int_length+=(uint) strlen(*pos)+1; // field + suffix prefix
805  int_parts+=field->interval->count+1;
806  }
807  }
808  if (f_maybe_null(field->pack_flag))
809  null_fields++;
810  }
811  int_length+=int_count*2; // 255 prefix + 0 suffix
812 
813  /* Save values in forminfo */
814 
815  if (reclength > (ulong) file->max_record_length())
816  {
817  my_error(ER_TOO_BIG_ROWSIZE, MYF(0), static_cast<long>(file->max_record_length()));
818  DBUG_RETURN(1);
819  }
820  /* Hack to avoid bugs with small static rows in MySQL */
821  reclength= max<size_t>(file->min_record_length(table_options), reclength);
822  if (info_length+(ulong) create_fields.elements*FCOMP+288+
823  n_length+int_length+com_length > 65535L || int_count > 255)
824  {
825  my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
826  DBUG_RETURN(1);
827  }
828 
829  memset(forminfo, 0, 288);
830  length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+
831  com_length);
832  int2store(forminfo,length);
833  forminfo[256] = (uint8) screens;
834  int2store(forminfo+258,create_fields.elements);
835  int2store(forminfo+260,info_length);
836  int2store(forminfo+262,totlength);
837  int2store(forminfo+264,no_empty);
838  int2store(forminfo+266,reclength);
839  int2store(forminfo+268,n_length);
840  int2store(forminfo+270,int_count);
841  int2store(forminfo+272,int_parts);
842  int2store(forminfo+274,int_length);
843  int2store(forminfo+276,time_stamp_pos);
844  int2store(forminfo+278,80); /* Columns needed */
845  int2store(forminfo+280,22); /* Rows needed */
846  int2store(forminfo+282,null_fields);
847  int2store(forminfo+284,com_length);
848  /* Up to forminfo+288 is free to use for additional information */
849  DBUG_RETURN(0);
850 } /* pack_header */
851 
852 
853  /* get each unique interval each own id */
854 
855 static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
856  Create_field *last_field)
857 {
858  List_iterator<Create_field> it(create_fields);
859  Create_field *field;
860  TYPELIB *interval=last_field->interval;
861 
862  while ((field=it++) != last_field)
863  {
864  if (field->interval_id && field->interval->count == interval->count)
865  {
866  const char **a,**b;
867  for (a=field->interval->type_names, b=interval->type_names ;
868  *a && !strcmp(*a,*b);
869  a++,b++) ;
870 
871  if (! *a)
872  {
873  return field->interval_id; // Re-use last interval
874  }
875  }
876  }
877  return ++*int_count; // New unique interval
878 }
879 
880 
881  /* Save fields, fieldnames and intervals */
882 
883 static bool pack_fields(File file, List<Create_field> &create_fields,
884  ulong data_offset)
885 {
886  reg2 uint i;
887  uint int_count, comment_length=0;
888  uchar buff[MAX_FIELD_WIDTH];
889  Create_field *field;
890  DBUG_ENTER("pack_fields");
891 
892  /* Write field info */
893 
894  List_iterator<Create_field> it(create_fields);
895 
896  int_count=0;
897  while ((field=it++))
898  {
899  uint recpos;
900  buff[0]= (uchar) field->row;
901  buff[1]= (uchar) field->col;
902  buff[2]= (uchar) field->sc_length;
903  int2store(buff+3, field->length);
904  /* The +1 is here becasue the col offset in .frm file have offset 1 */
905  recpos= field->offset+1 + (uint) data_offset;
906  int3store(buff+5,recpos);
907  int2store(buff+8,field->pack_flag);
908  DBUG_ASSERT(field->unireg_check < 256);
909  buff[10]= (uchar) field->unireg_check;
910  buff[12]= (uchar) field->interval_id;
911  buff[13]= (uchar) field->sql_type;
912  if (field->sql_type == MYSQL_TYPE_GEOMETRY)
913  {
914  buff[11]= 0;
915  buff[14]= (uchar) field->geom_type;
916 #ifndef HAVE_SPATIAL
917  DBUG_ASSERT(0); // Should newer happen
918 #endif
919  }
920  else if (field->charset)
921  {
922  buff[11]= (uchar) (field->charset->number >> 8);
923  buff[14]= (uchar) field->charset->number;
924  }
925  else
926  {
927  buff[11]= buff[14]= 0; // Numerical
928  }
929  int2store(buff+15, field->comment.length);
930  comment_length+= field->comment.length;
931  set_if_bigger(int_count,field->interval_id);
932  if (mysql_file_write(file, buff, FCOMP, MYF_RW))
933  DBUG_RETURN(1);
934  }
935 
936  /* Write fieldnames */
937  buff[0]=(uchar) NAMES_SEP_CHAR;
938  if (mysql_file_write(file, buff, 1, MYF_RW))
939  DBUG_RETURN(1);
940  i=0;
941  it.rewind();
942  while ((field=it++))
943  {
944  char *pos= strmov((char*) buff,field->field_name);
945  *pos++=NAMES_SEP_CHAR;
946  if (i == create_fields.elements-1)
947  *pos++=0;
948  if (mysql_file_write(file, buff, (size_t) (pos-(char*) buff), MYF_RW))
949  DBUG_RETURN(1);
950  i++;
951  }
952 
953  /* Write intervals */
954  if (int_count)
955  {
956  String tmp((char*) buff,sizeof(buff), &my_charset_bin);
957  tmp.length(0);
958  it.rewind();
959  int_count=0;
960  while ((field=it++))
961  {
962  if (field->interval_id > int_count)
963  {
964  unsigned char sep= 0;
965  unsigned char occ[256];
966  uint i;
967  unsigned char *val= NULL;
968 
969  memset(occ, 0, sizeof(occ));
970 
971  for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++)
972  for (uint j = 0; j < field->interval->type_lengths[i]; j++)
973  occ[(unsigned int) (val[j])]= 1;
974 
975  if (!occ[(unsigned char)NAMES_SEP_CHAR])
976  sep= (unsigned char) NAMES_SEP_CHAR;
977  else if (!occ[(unsigned int)','])
978  sep= ',';
979  else
980  {
981  for (uint i=1; i<256; i++)
982  {
983  if(!occ[i])
984  {
985  sep= i;
986  break;
987  }
988  }
989 
990  if(!sep) /* disaster, enum uses all characters, none left as separator */
991  {
992  my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
993  MYF(0));
994  DBUG_RETURN(1);
995  }
996  }
997 
998  int_count= field->interval_id;
999  tmp.append(sep);
1000  for (const char **pos=field->interval->type_names ; *pos ; pos++)
1001  {
1002  tmp.append(*pos);
1003  tmp.append(sep);
1004  }
1005  tmp.append('\0'); // End of intervall
1006  }
1007  }
1008  if (mysql_file_write(file, (uchar*) tmp.ptr(), tmp.length(), MYF_RW))
1009  DBUG_RETURN(1);
1010  }
1011  if (comment_length)
1012  {
1013  it.rewind();
1014  int_count=0;
1015  while ((field=it++))
1016  {
1017  if (field->comment.length)
1018  if (mysql_file_write(file, (uchar*) field->comment.str,
1019  field->comment.length, MYF_RW))
1020  DBUG_RETURN(1);
1021  }
1022  }
1023  DBUG_RETURN(0);
1024 }
1025 
1026 
1052 static bool make_empty_rec(THD *thd, File file,
1053  uint table_options,
1054  List<Create_field> &create_fields,
1055  uint reclength,
1056  ulong data_offset,
1057  handler *handler)
1058 {
1059  int error= 0;
1060  Field::utype type;
1061  uint null_count;
1062  uchar *buff,*null_pos;
1063  TABLE table;
1064  TABLE_SHARE share;
1065  Create_field *field;
1066  enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
1067  DBUG_ENTER("make_empty_rec");
1068 
1069  /* We need a table to generate columns for default values */
1070  memset(&table, 0, sizeof(table));
1071  memset(&share, 0, sizeof(share));
1072  table.s= &share;
1073 
1074  if (!(buff=(uchar*) my_malloc((size_t) reclength,MYF(MY_WME | MY_ZEROFILL))))
1075  {
1076  DBUG_RETURN(1);
1077  }
1078 
1079  table.in_use= thd;
1080  table.s->db_low_byte_first= handler->low_byte_first();
1081 
1082  null_count=0;
1083  if (!(table_options & HA_OPTION_PACK_RECORD))
1084  {
1085  null_count++; // Need one bit for delete mark
1086  *buff|= 1;
1087  }
1088  null_pos= buff;
1089 
1090  List_iterator<Create_field> it(create_fields);
1091  thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values
1092  while ((field=it++))
1093  {
1094  Field *regfield= make_field(&share,
1095  buff+field->offset + data_offset,
1096  field->length,
1097  null_pos + null_count / 8,
1098  null_count & 7,
1099  field->pack_flag,
1100  field->sql_type,
1101  field->charset,
1102  field->geom_type,
1103  field->unireg_check,
1104  field->save_interval ? field->save_interval :
1105  field->interval,
1106  field->field_name);
1107  if (!regfield)
1108  {
1109  error= 1;
1110  goto err; // End of memory
1111  }
1112 
1113  /* save_in_field() will access regfield->table->in_use */
1114  regfield->init(&table);
1115 
1116  if (!(field->flags & NOT_NULL_FLAG))
1117  {
1118  regfield->set_null();
1119  null_count++;
1120  }
1121 
1122  if (field->sql_type == MYSQL_TYPE_BIT && !f_bit_as_char(field->pack_flag))
1123  null_count+= field->length & 7;
1124 
1125  type= (Field::utype) MTYP_TYPENR(field->unireg_check);
1126 
1127  if (field->def)
1128  {
1129  /*
1130  Storing the value of a function is pointless as this function may not
1131  be constant.
1132  */
1133  DBUG_ASSERT(field->def->type() != Item::FUNC_ITEM);
1134  type_conversion_status res= field->def->save_in_field(regfield, 1);
1135  if (res != TYPE_OK && res != TYPE_NOTE_TIME_TRUNCATED &&
1136  res != TYPE_NOTE_TRUNCATED)
1137  {
1138  /*
1139  clear current error and report INVALID DEFAULT value error message
1140  */
1141  if (thd->is_error())
1142  thd->clear_error();
1143 
1144  my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
1145  error= 1;
1146  /*
1147  Delete to avoid memory leak for fields that allocate extra
1148  memory (e.g Field_blob::value)
1149  */
1150  delete regfield;
1151  goto err;
1152  }
1153  }
1154  else if (regfield->real_type() == MYSQL_TYPE_ENUM &&
1155  (field->flags & NOT_NULL_FLAG))
1156  {
1157  regfield->set_notnull();
1158  regfield->store((longlong) 1, TRUE);
1159  }
1160  else if (type == Field::YES) // Old unireg type
1161  regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)),system_charset_info);
1162  else if (type == Field::NO) // Old unireg type
1163  regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),system_charset_info);
1164  else
1165  regfield->reset();
1166  /*
1167  Delete to avoid memory leak for fields that allocate extra
1168  memory (e.g Field_blob::value)
1169  */
1170  delete regfield;
1171  }
1172  DBUG_ASSERT(data_offset == ((null_count + 7) / 8));
1173 
1174  /*
1175  We need to set the unused bits to 1. If the number of bits is a multiple
1176  of 8 there are no unused bits.
1177  */
1178  if (null_count & 7)
1179  *(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
1180 
1181  error= mysql_file_write(file, buff, (size_t) reclength, MYF_RW) != 0;
1182 
1183 err:
1184  my_free(buff);
1185  thd->count_cuted_fields= old_count_cuted_fields;
1186  DBUG_RETURN(error);
1187 } /* make_empty_rec */