1 /*
2 Copyright (c) 2000, 2018, 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, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 /*
26 Functions to create a unireg form-file from a FIELD and a fieldname-fieldinfo
27 struct.
28 In the following functions FIELD * is an ordinary field-structure with
29 the following exeptions:
30 sc_length,typepos,row,kol,dtype,regnr and field need not to be set.
31 str is a (long) to record position where 0 is the first position.
32 */
33
34 #include "unireg.h"
35 #include "table.h"
36 #include "sql_class.h" // THD, Internal_error_handler
37 #include "partition_info.h" // partition_info
38 #include "sql_table.h" // validate_comment_length
39
40 #include "pfs_file_provider.h"
41 #include "mysql/psi/mysql_file.h"
42
43 #include <algorithm>
44
45 using std::min;
46 using std::max;
47
48 #define FCOMP 17 /* Bytes for a packed field */
49 #define SC_INFO_LENGTH 4 /* Form format constant */
50 #define TE_INFO_LENGTH 3
51 #define MTYP_NOEMPTY_BIT 128
52
53 static uchar * pack_screens(List<Create_field> &create_fields,
54 uint *info_length, uint *screens, bool small_file);
55 static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
56 ulong data_offset);
57 static bool pack_header(uchar *forminfo,enum legacy_db_type table_type,
58 List<Create_field> &create_fields,
59 uint info_length, uint screens, uint table_options,
60 ulong data_offset, handler *file);
61 static uint get_interval_id(uint *,List<Create_field> &, Create_field *);
62 static bool pack_fields(File file, List<Create_field> &create_fields,
63 ulong data_offset);
64 static bool make_empty_rec(THD *thd, int file,
65 uint table_options,
66 List<Create_field> &create_fields,
67 uint reclength, ulong data_offset,
68 handler *handler);
69 /**
70 An interceptor to hijack ER_TOO_MANY_FIELDS error from
71 pack_screens and retry again without UNIREG screens.
72
73 XXX: what is a UNIREG screen?
74 */
75
76 class Pack_header_error_handler: public Internal_error_handler
77 {
78 bool m_is_handled;
79 public:
handle_condition(THD * thd,uint sql_errno,const char * sqlstate,Sql_condition::enum_severity_level * level,const char * msg)80 virtual bool handle_condition(THD *thd,
81 uint sql_errno,
82 const char* sqlstate,
83 Sql_condition::enum_severity_level *level,
84 const char* msg)
85 {
86 m_is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
87 return m_is_handled;
88 }
Pack_header_error_handler()89 Pack_header_error_handler() :m_is_handled(false) {}
is_handled() const90 bool is_handled() const { return m_is_handled; }
91 };
92
93
94 /*
95 Create a frm (table definition) file
96
97 SYNOPSIS
98 mysql_create_frm()
99 thd Thread handler
100 file_name Path for file (including database and .frm)
101 db Name of database
102 table Name of table
103 create_info create info parameters
104 create_fields Fields to create
105 keys number of keys to create
106 key_info Keys to create
107 db_file Handler to use. May be zero, in which case we use
108 create_info->db_type
109 RETURN
110 false ok
111 true error
112 */
113
mysql_create_frm(THD * thd,const char * file_name,const char * db,const char * table,HA_CREATE_INFO * create_info,List<Create_field> & create_fields,uint keys,KEY * key_info,handler * db_file)114 bool mysql_create_frm(THD *thd, const char *file_name,
115 const char *db, const char *table,
116 HA_CREATE_INFO *create_info,
117 List<Create_field> &create_fields,
118 uint keys, KEY *key_info,
119 handler *db_file)
120 {
121 LEX_STRING str_db_type;
122 uint reclength, info_length, screens, key_info_length, maxlength, i;
123 ulong key_buff_length;
124 File file;
125 ulong filepos, data_offset;
126 uchar fileinfo[64],forminfo[288],*keybuff, *forminfo_p= forminfo;
127 uchar *screen_buff= NULL;
128 char buff[128];
129 partition_info *part_info= thd->work_part_info;
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 size_t 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 if (part_info)
191 {
192 create_info->extra_size+= part_info->part_info_len;
193 }
194
195 for (i= 0; i < keys; i++)
196 {
197 if (key_info[i].parser_name)
198 create_info->extra_size+= key_info[i].parser_name->length + 1;
199 }
200 /*
201 This gives us the byte-position of the character at
202 (character-position, not byte-position) TABLE_COMMENT_MAXLEN.
203 The trick here is that character-positions start at 0, so the last
204 character in a maximum-allowed length string would be at char-pos
205 MAXLEN-1; charpos MAXLEN will be the position of the terminator.
206 Consequently, bytepos(charpos(MAXLEN)) should be equal to
207 comment[length] (which should also be the terminator, or at least
208 the first byte after the payload in the strict sense). If this is
209 not so (bytepos(charpos(MAXLEN)) comes /before/ the end of the
210 string), the string is too long.
211
212 For additional credit, realise that UTF-8 has 1-3 bytes before 6.0,
213 and 1-4 bytes in 6.0 (6.0 also has UTF-32).
214 */
215 if (create_info->comment.length > TABLE_COMMENT_MAXLEN)
216 {
217 const char *real_table_name= table;
218 List_iterator<Create_field> it(create_fields);
219 Create_field *field;
220 while ((field=it++))
221 {
222 if (field->field && field->field->table &&
223 (real_table_name= field->field->table->s->table_name.str))
224 break;
225 }
226 if (validate_comment_length(thd,
227 create_info->comment.str,
228 &create_info->comment.length,
229 TABLE_COMMENT_MAXLEN,
230 ER_TOO_LONG_TABLE_COMMENT,
231 real_table_name))
232 {
233 my_free(screen_buff);
234 DBUG_RETURN(true);
235 }
236 }
237 /*
238 If table comment is longer than TABLE_COMMENT_INLINE_MAXLEN bytes,
239 store the comment in an extra segment (up to TABLE_COMMENT_MAXLEN bytes).
240 Pre 6.0, the limit was 60 characters, with no extra segment-handling.
241 */
242 if (create_info->comment.length > TABLE_COMMENT_INLINE_MAXLEN)
243 {
244 forminfo[46]=255;
245 create_info->extra_size+= 2 + create_info->comment.length;
246 }
247 else{
248 strmake((char*) forminfo+47, create_info->comment.str ?
249 create_info->comment.str : "", create_info->comment.length);
250 forminfo[46]=(uchar) create_info->comment.length;
251 }
252
253 /*
254 Add room in extra segment for "format section" with additional
255 table and column properties
256 */
257 if (create_info->tablespace)
258 {
259 tablespace_length= strlen(create_info->tablespace);
260 /*
261 Make sure we have at least an IX lock on the tablespace name,
262 unless this is a temporary table. For temporary tables, the
263 tablespace name is not IX locked.
264 */
265 if (tablespace_length > 0 &&
266 !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
267 DBUG_ASSERT(thd->mdl_context.owns_equal_or_stronger_lock(
268 MDL_key::TABLESPACE, "",
269 create_info->tablespace,
270 MDL_INTENTION_EXCLUSIVE));
271 }
272 format_section_length=
273 format_section_header_size +
274 tablespace_length + 1 +
275 create_fields.elements;
276 create_info->extra_size+= format_section_length;
277
278 create_info->extra_size+= 2 + create_info->compress.length;
279
280 create_info->extra_size+= 2 + create_info->encrypt_type.length;
281
282 if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
283 create_info, keys, key_info)) < 0)
284 {
285 my_free(screen_buff);
286 DBUG_RETURN(1);
287 }
288
289 key_buff_length= uint4korr(fileinfo+47);
290 keybuff=(uchar*) my_malloc(key_memory_frm,
291 key_buff_length, MYF(0));
292 key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
293
294 /* key_info_length is currently stored in 2 bytes */
295 if (key_info_length > 65535U)
296 {
297 char *real_table_name= (char*) table;
298 List_iterator<Create_field> it(create_fields);
299 Create_field *field;
300 while ((field=it++))
301 {
302 if (field->field && field->field->table &&
303 (real_table_name= field->field->table->s->table_name.str))
304 break;
305 }
306 my_printf_error(ER_UNKNOWN_ERROR,
307 "Index information size for the table %s.%s exceeds the "
308 "maximum limit (Max: 2 bytes). Please recreate indexes "
309 "accordingly.", MYF(0), db, real_table_name);
310 goto err;
311 }
312
313 /*
314 Ensure that there are no forms in this newly created form file.
315 Even if the form file exists, create_frm must truncate it to
316 ensure one form per form file.
317 */
318 DBUG_ASSERT(uint2korr(fileinfo+8) == 0);
319
320 if (!(filepos= make_new_entry(file, fileinfo, NULL, "")))
321 goto err;
322 maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo_p)+1000));
323 int2store(forminfo+2,maxlength);
324 int4store(fileinfo+10,(ulong) (filepos+maxlength));
325 fileinfo[26]= (uchar) MY_TEST((create_info->max_rows == 1) &&
326 (create_info->min_rows == 1) && (keys == 0));
327 int2store(fileinfo+28,key_info_length);
328
329 if (part_info)
330 {
331 fileinfo[61]= (uchar) ha_legacy_type(part_info->default_engine_type);
332 DBUG_PRINT("info", ("part_db_type = %d", fileinfo[61]));
333 }
334 int2store(fileinfo+59,db_file->extra_rec_buf_length());
335
336 if (mysql_file_pwrite(file, fileinfo, 64, 0L, MYF_RW) ||
337 mysql_file_pwrite(file, keybuff, key_info_length,
338 (ulong) uint2korr(fileinfo+6), MYF_RW))
339 goto err;
340 mysql_file_seek(file,
341 (ulong) uint2korr(fileinfo+6) + (ulong) key_buff_length,
342 MY_SEEK_SET, MYF(0));
343 if (make_empty_rec(thd,file,
344 create_info->table_options,
345 create_fields,reclength, data_offset, db_file))
346 goto err;
347
348 int2store(buff, static_cast<uint16>(create_info->connect_string.length));
349 if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
350 mysql_file_write(file, (const uchar*)create_info->connect_string.str,
351 create_info->connect_string.length, MYF(MY_NABP)))
352 goto err;
353
354 int2store(buff, static_cast<uint16>(str_db_type.length));
355 if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
356 mysql_file_write(file, (const uchar*)str_db_type.str,
357 str_db_type.length, MYF(MY_NABP)))
358 goto err;
359
360 if (part_info)
361 {
362 char auto_partitioned= part_info->is_auto_partitioned ? 1 : 0;
363 int4store(buff, static_cast<uint32>(part_info->part_info_len));
364 if (mysql_file_write(file, (const uchar*)buff, 4, MYF_RW) ||
365 mysql_file_write(file, (const uchar*)part_info->part_info_string,
366 part_info->part_info_len + 1, MYF_RW) ||
367 mysql_file_write(file, (const uchar*)&auto_partitioned, 1, MYF_RW))
368 goto err;
369 }
370 else
371 {
372 memset(buff, 0, 6);
373 if (mysql_file_write(file, (uchar*) buff, 6, MYF_RW))
374 goto err;
375 }
376 for (i= 0; i < keys; i++)
377 {
378 if (key_info[i].parser_name)
379 {
380 if (mysql_file_write(file, (const uchar*)key_info[i].parser_name->str,
381 key_info[i].parser_name->length + 1, MYF(MY_NABP)))
382 goto err;
383 }
384 }
385 if (forminfo[46] == (uchar)255)
386 {
387 uchar comment_length_buff[2];
388 int2store(comment_length_buff, static_cast<uint16>(create_info->comment.length));
389 if (mysql_file_write(file, comment_length_buff, 2, MYF(MY_NABP)) ||
390 mysql_file_write(file, (uchar*) create_info->comment.str,
391 create_info->comment.length, MYF(MY_NABP)))
392 goto err;
393 }
394
395 /* "Format section" with additional table and column properties */
396 {
397 uchar *ptr, *format_section_buff;
398 if (!(format_section_buff=(uchar*) my_malloc(key_memory_frm,
399 format_section_length,
400 MYF(MY_WME))))
401 goto err;
402 ptr= format_section_buff;
403
404 /* header */
405 const uint format_section_flags=
406 create_info->storage_media; // 3 bits
407 const uint format_section_unused= 0;
408 int2store(ptr+0, format_section_length);
409 int4store(ptr+2, format_section_flags);
410 int2store(ptr+6, format_section_unused);
411 ptr+= format_section_header_size;
412
413 /* tablespace name */
414 if (tablespace_length > 0)
415 memcpy(ptr, create_info->tablespace, tablespace_length);
416 ptr+= tablespace_length;
417 *ptr= 0; /* tablespace string terminating zero */
418 ptr++;
419
420 /* column properties */
421 Create_field *field;
422 List_iterator<Create_field> it(create_fields);
423 while ((field=it++))
424 {
425 const uchar field_storage= field->field_storage_type();
426 const uchar field_column_format= field->column_format();
427 const uchar field_flags=
428 field_storage + (field_column_format << COLUMN_FORMAT_SHIFT);
429 *ptr= field_flags;
430 ptr++;
431 }
432 DBUG_ASSERT(format_section_buff + format_section_length == ptr);
433
434 if (mysql_file_write(file, format_section_buff,
435 format_section_length, MYF_RW))
436 {
437 my_free(format_section_buff);
438 goto err;
439 }
440 DBUG_PRINT("info", ("wrote format section, length: %u",
441 format_section_length));
442 my_free(format_section_buff);
443 }
444
445 /* Write out the COMPRESS table attribute */
446 {
447 uchar length_buff[2];
448
449 int2store(length_buff, static_cast<uint16>(create_info->compress.length));
450
451 if (mysql_file_write(file, length_buff, 2, MYF(MY_NABP)) ||
452 mysql_file_write(file, (uchar*) create_info->compress.str,
453 create_info->compress.length, MYF(MY_NABP)))
454 goto err;
455 }
456
457 /* Write out the ENCRYPT table attribute */
458 {
459 uchar length_buff[2];
460
461 int2store(length_buff,
462 static_cast<uint16>(create_info->encrypt_type.length));
463
464 if (mysql_file_write(file, length_buff, 2, MYF(MY_NABP)) ||
465 mysql_file_write(file, (uchar*) create_info->encrypt_type.str,
466 create_info->encrypt_type.length, MYF(MY_NABP)))
467 goto err;
468 }
469
470 mysql_file_seek(file, filepos, MY_SEEK_SET, MYF(0));
471 if (mysql_file_write(file, forminfo, 288, MYF_RW) ||
472 mysql_file_write(file, screen_buff, info_length, MYF_RW) ||
473 pack_fields(file, create_fields, data_offset))
474 goto err;
475
476 my_free(screen_buff);
477 my_free(keybuff);
478
479 if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
480 (mysql_file_sync(file, MYF(MY_WME)) ||
481 my_sync_dir_by_file(file_name, MYF(MY_WME))))
482 goto err2;
483
484 if (mysql_file_close(file, MYF(MY_WME)))
485 goto err3;
486
487 {
488 /*
489 Restore all UCS2 intervals.
490 HEX representation of them is not needed anymore.
491 */
492 List_iterator<Create_field> it(create_fields);
493 Create_field *field;
494 while ((field=it++))
495 {
496 if (field->save_interval)
497 {
498 field->interval= field->save_interval;
499 field->save_interval= 0;
500 }
501 }
502 }
503 DBUG_RETURN(0);
504
505 err:
506 my_free(screen_buff);
507 my_free(keybuff);
508 err2:
509 (void) mysql_file_close(file, MYF(MY_WME));
510 err3:
511 mysql_file_delete(key_file_frm, file_name, MYF(0));
512 DBUG_RETURN(1);
513 } /* mysql_create_frm */
514
515
516 /**
517 Create a frm (table definition) file and the tables
518
519 @param thd Thread handler
520 @param path Name of file (including database, without .frm)
521 @param db Data base name
522 @param table_name Table name
523 @param create_info create info parameters
524 @param create_fields Fields to create
525 @param keys number of keys to create
526 @param key_info Keys to create
527 @param file Handler to use
528 @param no_ha_table Indicates that only .FRM file (and PAR file if table
529 is partitioned) needs to be created and not a table
530 in the storage engine.
531
532 @retval 0 ok
533 @retval 1 error
534 */
535
rea_create_table(THD * thd,const char * path,const char * db,const char * table_name,HA_CREATE_INFO * create_info,List<Create_field> & create_fields,uint keys,KEY * key_info,handler * file,bool no_ha_table)536 int rea_create_table(THD *thd, const char *path,
537 const char *db, const char *table_name,
538 HA_CREATE_INFO *create_info,
539 List<Create_field> &create_fields,
540 uint keys, KEY *key_info, handler *file,
541 bool no_ha_table)
542 {
543 DBUG_ENTER("rea_create_table");
544
545 char frm_name[FN_REFLEN + 1];
546 strxnmov(frm_name, sizeof(frm_name) - 1, path, reg_ext, NullS);
547
548 if (mysql_create_frm(thd, frm_name, db, table_name, create_info,
549 create_fields, keys, key_info, file))
550
551 DBUG_RETURN(1);
552
553 // Make sure mysql_create_frm din't remove extension
554 DBUG_ASSERT(*fn_rext(frm_name));
555 if (thd->variables.keep_files_on_create)
556 create_info->options|= HA_CREATE_KEEP_FILES;
557
558 if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG,
559 create_info))
560 goto err_handler_frm;
561
562 if (!no_ha_table &&
563 ha_create_table(thd, path, db, table_name, create_info, 0))
564 goto err_handler;
565 DBUG_RETURN(0);
566
567 err_handler:
568 (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
569
570 err_handler_frm:
571 mysql_file_delete(key_file_frm, frm_name, MYF(0));
572 DBUG_RETURN(1);
573 } /* rea_create_table */
574
575
576 /* Pack screens to a screen for save in a form-file */
577
pack_screens(List<Create_field> & create_fields,uint * info_length,uint * screens,bool small_file)578 static uchar *pack_screens(List<Create_field> &create_fields,
579 uint *info_length, uint *screens,
580 bool small_file)
581 {
582 uint i;
583 uint row,start_row,end_row,fields_on_screen;
584 size_t length;
585 uint cols;
586 uchar *info,*pos,*start_screen;
587 uint fields=create_fields.elements;
588 List_iterator<Create_field> it(create_fields);
589 DBUG_ENTER("pack_screens");
590
591 start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;
592
593 *screens=(fields-1)/fields_on_screen+1;
594 length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);
595
596 Create_field *field;
597 while ((field=it++))
598 length+= strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
599
600 if (!(info=(uchar*) my_malloc(key_memory_frm,
601 length,MYF(MY_WME))))
602 DBUG_RETURN(0);
603
604 start_screen=0;
605 row=end_row;
606 pos=info;
607 it.rewind();
608 for (i=0 ; i < fields ; i++)
609 {
610 Create_field *cfield=it++;
611 if (row++ == end_row)
612 {
613 if (i)
614 {
615 length=(uint) (pos-start_screen);
616 int2store(start_screen, static_cast<uint16>(length));
617 start_screen[2]=(uchar) (fields_on_screen+1);
618 start_screen[3]=(uchar) (fields_on_screen);
619 }
620 row=start_row;
621 start_screen=pos;
622 pos+=4;
623 pos[0]= (uchar) start_row-2; /* Header string */
624 pos[1]= (uchar) (cols >> 2);
625 pos[2]= (uchar) (cols >> 1) +1;
626 strfill((char *) pos+3,(uint) (cols >> 1),' ');
627 pos+=(cols >> 1)+4;
628 }
629 length= strlen(cfield->field_name);
630 if (length > cols-3)
631 length=cols-3;
632
633 if (!small_file)
634 {
635 pos[0]=(uchar) row;
636 pos[1]=0;
637 pos[2]=(uchar) (length+1);
638 pos=(uchar*) strmake((char*) pos+3,cfield->field_name,length)+1;
639 }
640 cfield->row=(uint8) row;
641 cfield->col=(uint8) (length+1);
642 cfield->sc_length= min<uint8>(cfield->length, cols - (length + 2));
643 }
644 length=(uint) (pos-start_screen);
645 int2store(start_screen, static_cast<uint16>(length));
646 start_screen[2]=(uchar) (row-start_row+2);
647 start_screen[3]=(uchar) (row-start_row+1);
648
649 *info_length=(uint) (pos-info);
650 DBUG_RETURN(info);
651 } /* pack_screens */
652
653
654 /* Pack keyinfo and keynames to keybuff for save in form-file. */
655
pack_keys(uchar * keybuff,uint key_count,KEY * keyinfo,ulong data_offset)656 static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
657 ulong data_offset)
658 {
659 uint key_parts,length;
660 uchar *pos, *keyname_pos;
661 KEY *key,*end;
662 KEY_PART_INFO *key_part,*key_part_end;
663 DBUG_ENTER("pack_keys");
664
665 pos=keybuff+6;
666 key_parts=0;
667 for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
668 {
669 int2store(pos, static_cast<uint16>(key->flags ^ HA_NOSAME));
670 int2store(pos+2,key->key_length);
671 pos[4]= (uchar) key->user_defined_key_parts;
672 pos[5]= (uchar) key->algorithm;
673 int2store(pos+6, key->block_size);
674 pos+=8;
675 key_parts+=key->user_defined_key_parts;
676 DBUG_PRINT("loop", ("flags: %lu key_parts: %d at 0x%lx",
677 key->flags, key->user_defined_key_parts,
678 (long) key->key_part));
679 for (key_part=key->key_part,
680 key_part_end= key_part + key->user_defined_key_parts ;
681 key_part != key_part_end ;
682 key_part++)
683
684 {
685 uint offset;
686 DBUG_PRINT("loop",("field: %d startpos: %lu length: %d",
687 key_part->fieldnr, key_part->offset + data_offset,
688 key_part->length));
689 int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
690 offset= (uint) (key_part->offset+data_offset+1);
691 int2store(pos+2, offset);
692 pos[4]=0; // Sort order
693 int2store(pos+5,key_part->key_type);
694 int2store(pos+7,key_part->length);
695 pos+=9;
696 }
697 }
698 /* Save keynames */
699 keyname_pos=pos;
700 *pos++=(uchar) NAMES_SEP_CHAR;
701 for (key=keyinfo ; key != end ; key++)
702 {
703 uchar *tmp=(uchar*) my_stpcpy((char*) pos,key->name);
704 *tmp++= (uchar) NAMES_SEP_CHAR;
705 *tmp=0;
706 pos=tmp;
707 }
708 *(pos++)=0;
709 for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
710 {
711 if (key->flags & HA_USES_COMMENT)
712 {
713 int2store(pos, static_cast<uint16>(key->comment.length));
714 uchar *tmp= (uchar*)my_stpnmov((char*) pos+2,key->comment.str,
715 key->comment.length);
716 pos= tmp;
717 }
718 }
719
720 if (key_count > 127 || key_parts > 127)
721 {
722 keybuff[0]= (key_count & 0x7f) | 0x80;
723 keybuff[1]= key_count >> 7;
724 int2store(keybuff+2,key_parts);
725 }
726 else
727 {
728 keybuff[0]=(uchar) key_count;
729 keybuff[1]=(uchar) key_parts;
730 keybuff[2]= keybuff[3]= 0;
731 }
732 length=(uint) (pos-keyname_pos);
733 int2store(keybuff+4,length);
734 DBUG_RETURN((uint) (pos-keybuff));
735 } /* pack_keys */
736
737
738 /* Make formheader */
739
pack_header(uchar * forminfo,enum legacy_db_type table_type,List<Create_field> & create_fields,uint info_length,uint screens,uint table_options,ulong data_offset,handler * file)740 static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
741 List<Create_field> &create_fields,
742 uint info_length, uint screens, uint table_options,
743 ulong data_offset, handler *file)
744 {
745 size_t length;
746 uint int_count, int_length, no_empty, int_parts;
747 uint time_stamp_pos,null_fields;
748 size_t reclength, totlength, n_length, com_length, gcol_info_length;
749 DBUG_ENTER("pack_header");
750
751 if (create_fields.elements > MAX_FIELDS)
752 {
753 my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
754 DBUG_RETURN(1);
755 }
756
757 totlength= 0L;
758 reclength= data_offset;
759 no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=0;
760 com_length=gcol_info_length=0;
761 n_length=2L;
762
763 /* Check fields */
764
765 List_iterator<Create_field> it(create_fields);
766 Create_field *field;
767 while ((field=it++))
768 {
769 THD *thd= current_thd;
770
771 if (validate_comment_length(thd,
772 field->comment.str,
773 &field->comment.length,
774 COLUMN_COMMENT_MAXLEN,
775 ER_TOO_LONG_FIELD_COMMENT,
776 (char *) field->field_name))
777 DBUG_RETURN(true);
778 if (field->gcol_info)
779 {
780 sql_mode_t sql_mode= thd->variables.sql_mode;
781 thd->variables.sql_mode&= ~MODE_ANSI_QUOTES;
782
783 /*
784 It is important to normalize the expression's text into the FRM, to
785 make it independent from sql_mode. For example, 'a||b' means 'a OR b'
786 or 'CONCAT(a,b)', depending on if PIPES_AS_CONCAT is on. Using
787 Item::print(), we get self-sufficient text containing 'OR' or
788 'CONCAT'. If sql_mode later changes, it will not affect the column.
789 */
790 String s;
791 // Printing db and table name is useless
792 field->gcol_info->expr_item->
793 print(&s, enum_query_type(QT_NO_DB | QT_NO_TABLE));
794
795 thd->variables.sql_mode= sql_mode;
796 /*
797 The new text must have exactly the same lifetime as the old text, it's
798 a replacement for it. So the same MEM_ROOT must be used: pass NULL.
799 */
800 field->gcol_info->dup_expr_str(NULL, s.ptr(), s.length());
801
802 uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
803 field->gcol_info->expr_str.str,
804 field->gcol_info->expr_str.str +
805 field->gcol_info->expr_str.length,
806 GENERATED_COLUMN_EXPRESSION_MAXLEN);
807
808 if (tmp_len < field->gcol_info->expr_str.length)
809 {
810 my_error(ER_WRONG_STRING_LENGTH, MYF(0),
811 field->gcol_info->expr_str.str,"GENERATED COLUMN EXPRESSION",
812 (uint) GENERATED_COLUMN_EXPRESSION_MAXLEN);
813 DBUG_RETURN(1);
814 }
815 /*
816 Sum up the length of the expression string and mandatory header bytes
817 to the total length.
818 */
819 gcol_info_length+= field->gcol_info->expr_str.length+(uint)FRM_GCOL_HEADER_SIZE;
820 }
821 totlength+= field->length;
822 com_length+= field->comment.length;
823 if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY ||
824 field->unireg_check & MTYP_NOEMPTY_BIT)
825 {
826 field->unireg_check= (Field::utype) ((uint) field->unireg_check |
827 MTYP_NOEMPTY_BIT);
828 no_empty++;
829 }
830 /*
831 We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE
832 as auto-update field.
833 */
834 if (field->sql_type == MYSQL_TYPE_TIMESTAMP &&
835 MTYP_TYPENR(field->unireg_check) != Field::NONE &&
836 !time_stamp_pos)
837 time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
838 length=field->pack_length;
839 /* Ensure we don't have any bugs when generating offsets */
840 /**
841 Because the virtual generated columns are not stored physically,
842 they are put at the tail of record. The details can be checked
843 in mysql_prepare_create_table. So the offset is messed up by
844 vitual generated columns. The original assert is not correct
845 any more.
846 DBUG_ASSERT(reclength == field->offset + data_offset);
847 */
848 if (field->offset + data_offset + length > reclength)
849 reclength= field->offset + data_offset + length;
850 n_length+= strlen(field->field_name) + 1;
851 field->interval_id=0;
852 field->save_interval= 0;
853 if (field->interval)
854 {
855 uint old_int_count=int_count;
856
857 if (field->charset->mbminlen > 1)
858 {
859 /*
860 Escape UCS2 intervals using HEX notation to avoid
861 problems with delimiters between enum elements.
862 As the original representation is still needed in
863 the function make_empty_rec to create a record of
864 filled with default values it is saved in save_interval
865 The HEX representation is created from this copy.
866 */
867 field->save_interval= field->interval;
868 field->interval= (TYPELIB*) sql_alloc(sizeof(TYPELIB));
869 *field->interval= *field->save_interval;
870 field->interval->type_names=
871 (const char **) sql_alloc(sizeof(char*) *
872 (field->interval->count+1));
873 field->interval->type_names[field->interval->count]= 0;
874 field->interval->type_lengths=
875 (uint *) sql_alloc(sizeof(uint) * field->interval->count);
876
877 for (uint pos= 0; pos < field->interval->count; pos++)
878 {
879 char *dst;
880 const char *src= field->save_interval->type_names[pos];
881 size_t hex_length;
882 length= field->save_interval->type_lengths[pos];
883 hex_length= length * 2;
884 field->interval->type_lengths[pos]= hex_length;
885 field->interval->type_names[pos]= dst= (char*) sql_alloc(hex_length +
886 1);
887 octet2hex(dst, src, length);
888 }
889 }
890
891 field->interval_id=get_interval_id(&int_count,create_fields,field);
892 if (old_int_count != int_count)
893 {
894 for (const char **pos=field->interval->type_names ; *pos ; pos++)
895 int_length+=(uint) strlen(*pos)+1; // field + suffix prefix
896 int_parts+=field->interval->count+1;
897 }
898 }
899 if (f_maybe_null(field->pack_flag))
900 null_fields++;
901 }
902 int_length+=int_count*2; // 255 prefix + 0 suffix
903
904 /* Save values in forminfo */
905
906 if (reclength > (ulong) file->max_record_length())
907 {
908 my_error(ER_TOO_BIG_ROWSIZE, MYF(0), static_cast<long>(file->max_record_length()));
909 DBUG_RETURN(1);
910 }
911 /* Hack to avoid bugs with small static rows in MySQL */
912 reclength= max<size_t>(file->min_record_length(table_options), reclength);
913 if (info_length + (ulong) create_fields.elements * FCOMP + 288 +
914 n_length + int_length + com_length + gcol_info_length > 65535L ||
915 int_count > 255)
916 {
917 my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
918 DBUG_RETURN(1);
919 }
920
921 memset(forminfo, 0, 288);
922 length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+
923 com_length + gcol_info_length);
924 int2store(forminfo, static_cast<uint16>(length));
925 forminfo[256] = (uint8) screens;
926 int2store(forminfo+258,create_fields.elements);
927 int2store(forminfo+260,info_length);
928 int2store(forminfo+262, static_cast<uint16>(totlength));
929 int2store(forminfo+264,no_empty);
930 int2store(forminfo+266, static_cast<uint16>(reclength));
931 int2store(forminfo+268, static_cast<uint16>(n_length));
932 int2store(forminfo+270,int_count);
933 int2store(forminfo+272,int_parts);
934 int2store(forminfo+274,int_length);
935 int2store(forminfo+276,time_stamp_pos);
936 int2store(forminfo+278,80); /* Columns needed */
937 int2store(forminfo+280,22); /* Rows needed */
938 int2store(forminfo+282,null_fields);
939 int2store(forminfo+284, static_cast<uint16>(com_length));
940 int2store(forminfo+286,gcol_info_length);
941 /* forminfo+288 is free to use for additional information */
942 DBUG_RETURN(0);
943 } /* pack_header */
944
945
946 /* get each unique interval each own id */
947
get_interval_id(uint * int_count,List<Create_field> & create_fields,Create_field * last_field)948 static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
949 Create_field *last_field)
950 {
951 List_iterator<Create_field> it(create_fields);
952 Create_field *field;
953 TYPELIB *interval=last_field->interval;
954
955 while ((field=it++) != last_field)
956 {
957 if (field->interval_id && field->interval->count == interval->count)
958 {
959 const char **a,**b;
960 for (a=field->interval->type_names, b=interval->type_names ;
961 *a && !strcmp(*a,*b);
962 a++,b++) ;
963
964 if (! *a)
965 {
966 return field->interval_id; // Re-use last interval
967 }
968 }
969 }
970 return ++*int_count; // New unique interval
971 }
972
973
974 /* Save fields, fieldnames and intervals */
975
pack_fields(File file,List<Create_field> & create_fields,ulong data_offset)976 static bool pack_fields(File file, List<Create_field> &create_fields,
977 ulong data_offset)
978 {
979 uint i;
980 uint int_count, gcol_info_length=0;
981 size_t comment_length= 0;
982 uchar buff[MAX_FIELD_WIDTH];
983 Create_field *field;
984 DBUG_ENTER("pack_fields");
985
986 /* Write field info */
987
988 List_iterator<Create_field> it(create_fields);
989
990 int_count=0;
991 while ((field=it++))
992 {
993 uint recpos;
994 buff[0]= (uchar) field->row;
995 buff[1]= (uchar) field->col;
996 buff[2]= (uchar) field->sc_length;
997 int2store(buff+3, static_cast<uint16>(field->length));
998 /* The +1 is here becasue the col offset in .frm file have offset 1 */
999 recpos= field->offset+1 + (uint) data_offset;
1000 int3store(buff+5,recpos);
1001 int2store(buff+8,field->pack_flag);
1002 buff[10]= (uchar) field->unireg_check;
1003 buff[12]= (uchar) field->interval_id;
1004 buff[13]= (uchar) field->sql_type;
1005 if (field->sql_type == MYSQL_TYPE_GEOMETRY)
1006 {
1007 buff[11]= 0;
1008 buff[14]= (uchar) field->geom_type;
1009 }
1010 else if (field->charset)
1011 {
1012 buff[11]= (uchar) (field->charset->number >> 8);
1013 buff[14]= (uchar) field->charset->number;
1014 }
1015 else
1016 {
1017 buff[11]= buff[14]= 0; // Numerical
1018 }
1019 if (field->gcol_info)
1020 {
1021 gcol_info_length+= field->gcol_info->expr_str.length;
1022 buff[10]|= (uchar)Field::GENERATED_FIELD;
1023 }
1024 int2store(buff+15, static_cast<uint16>(field->comment.length));
1025 comment_length+= field->comment.length;
1026 set_if_bigger(int_count,field->interval_id);
1027 if (mysql_file_write(file, buff, FCOMP, MYF_RW))
1028 DBUG_RETURN(1);
1029 }
1030
1031 /* Write fieldnames */
1032 buff[0]=(uchar) NAMES_SEP_CHAR;
1033 if (mysql_file_write(file, buff, 1, MYF_RW))
1034 DBUG_RETURN(1);
1035 i=0;
1036 it.rewind();
1037 while ((field=it++))
1038 {
1039 char *pos= my_stpcpy((char*) buff,field->field_name);
1040 *pos++=NAMES_SEP_CHAR;
1041 if (i == create_fields.elements-1)
1042 *pos++=0;
1043 if (mysql_file_write(file, buff, (size_t) (pos-(char*) buff), MYF_RW))
1044 DBUG_RETURN(1);
1045 i++;
1046 }
1047
1048 /* Write intervals */
1049 if (int_count)
1050 {
1051 String tmp((char*) buff,sizeof(buff), &my_charset_bin);
1052 tmp.length(0);
1053 it.rewind();
1054 int_count=0;
1055 while ((field=it++))
1056 {
1057 if (field->interval_id > int_count)
1058 {
1059 unsigned char sep= 0;
1060 unsigned char occ[256];
1061 uint i;
1062 unsigned char *val= NULL;
1063
1064 memset(occ, 0, sizeof(occ));
1065
1066 for (i=0; (val= (unsigned char*) field->interval->type_names[i]); i++)
1067 for (uint j = 0; j < field->interval->type_lengths[i]; j++)
1068 occ[(unsigned int) (val[j])]= 1;
1069
1070 if (!occ[(unsigned char)NAMES_SEP_CHAR])
1071 sep= (unsigned char) NAMES_SEP_CHAR;
1072 else if (!occ[(unsigned int)','])
1073 sep= ',';
1074 else
1075 {
1076 for (uint i=1; i<256; i++)
1077 {
1078 if(!occ[i])
1079 {
1080 sep= i;
1081 break;
1082 }
1083 }
1084
1085 if(!sep) /* disaster, enum uses all characters, none left as separator */
1086 {
1087 my_message(ER_WRONG_FIELD_TERMINATORS,ER(ER_WRONG_FIELD_TERMINATORS),
1088 MYF(0));
1089 DBUG_RETURN(1);
1090 }
1091 }
1092
1093 int_count= field->interval_id;
1094 tmp.append(sep);
1095 for (const char **pos=field->interval->type_names ; *pos ; pos++)
1096 {
1097 tmp.append(*pos);
1098 tmp.append(sep);
1099 }
1100 tmp.append('\0'); // End of intervall
1101 }
1102 }
1103 if (mysql_file_write(file, (uchar*) tmp.ptr(), tmp.length(), MYF_RW))
1104 DBUG_RETURN(1);
1105 }
1106 if (comment_length)
1107 {
1108 it.rewind();
1109 int_count=0;
1110 while ((field=it++))
1111 {
1112 if (field->comment.length)
1113 if (mysql_file_write(file, (uchar*) field->comment.str,
1114 field->comment.length, MYF_RW))
1115 DBUG_RETURN(1);
1116 }
1117 }
1118 if (gcol_info_length)
1119 {
1120 it.rewind();
1121 int_count=0;
1122 while ((field=it++))
1123 {
1124 /*
1125 Pack each virtual field as follows:
1126 byte 1 = 1 (always 1 to allow for future extensions)
1127 byte 2,3 = expression length
1128 byte 4 = flags, as of now:
1129 0 - no flags
1130 1 - field is physically stored
1131 byte 5-... = generated column expression (text data)
1132 */
1133 if (field->gcol_info && field->gcol_info->expr_str.length)
1134 {
1135 buff[0]= (uchar)1;
1136 int2store(buff + 1, field->gcol_info->expr_str.length);
1137 buff[3]= (uchar) field->stored_in_db;
1138 if (my_write(file, buff, FRM_GCOL_HEADER_SIZE, MYF_RW))
1139 DBUG_RETURN(1);
1140 if (my_write(file,
1141 (uchar*) field->gcol_info->expr_str.str,
1142 field->gcol_info->expr_str.length,
1143 MYF_RW))
1144 DBUG_RETURN(1);
1145 }
1146 }
1147 }
1148 DBUG_RETURN(0);
1149 }
1150
1151
1152 /**
1153 Auxiliary function which stores field's explicit or implicit default
1154 value in record buffer.
1155
1156 @param thd Connection's context.
1157 @param table Table for which field default value to be stored.
1158 @param field Field definition object.
1159 @param rec_pos Pointer to the main part of record buffer where
1160 field values are stored (as opposed to record
1161 preamble).
1162 @param null_pos Pointer to the preamble part of record buffer
1163 where null bits and leftover bits from BIT fields
1164 are stored.
1165 @param[in/out] null_count Index of bit in preamble to be used for storing
1166 NULL/leftover bits for the field if necessary. On
1167 return incremented by number of bits in preamble
1168 used for this field.
1169
1170 @retval true An error occured.
1171 @retval false Success.
1172 */
1173
make_default_value(THD * thd,TABLE * table,Create_field * field,uchar * rec_pos,uchar * null_pos,uint * null_count)1174 bool make_default_value(THD *thd, TABLE *table, Create_field *field,
1175 uchar *rec_pos, uchar *null_pos, uint *null_count)
1176 {
1177 Field *regfield= make_field(table->s,
1178 rec_pos + field->offset,
1179 field->length,
1180 null_pos + *null_count / 8,
1181 *null_count & 7,
1182 field->pack_flag,
1183 field->sql_type,
1184 field->charset,
1185 field->geom_type,
1186 field->unireg_check,
1187 field->save_interval ? field->save_interval :
1188 field->interval,
1189 field->field_name);
1190 if (!regfield)
1191 return true; // End of memory
1192
1193 /* save_in_field() will access regfield->table->in_use */
1194 regfield->init(table);
1195
1196 if (!(field->flags & NOT_NULL_FLAG))
1197 {
1198 regfield->set_null();
1199 (*null_count)++;
1200 }
1201
1202 if (field->sql_type == MYSQL_TYPE_BIT && !f_bit_as_char(field->pack_flag))
1203 (*null_count)+= field->length & 7;
1204
1205 Field::utype type= (Field::utype) MTYP_TYPENR(field->unireg_check);
1206
1207 if (field->def)
1208 {
1209 /*
1210 Storing the value of a function is pointless as this function may not
1211 be constant.
1212 */
1213 DBUG_ASSERT(field->def->type() != Item::FUNC_ITEM);
1214 type_conversion_status res= field->def->save_in_field(regfield, true);
1215 if (res != TYPE_OK && res != TYPE_NOTE_TIME_TRUNCATED &&
1216 res != TYPE_NOTE_TRUNCATED)
1217 {
1218 /*
1219 clear current error and report INVALID DEFAULT value error message
1220 */
1221 if (thd->is_error())
1222 thd->clear_error();
1223
1224 my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
1225 /*
1226 Delete to avoid memory leak for fields that allocate extra
1227 memory (e.g Field_blob::value)
1228 */
1229 delete regfield;
1230 return true;
1231 }
1232 }
1233 else if (regfield->real_type() == MYSQL_TYPE_ENUM &&
1234 (field->flags & NOT_NULL_FLAG))
1235 {
1236 regfield->set_notnull();
1237 regfield->store((longlong) 1, TRUE);
1238 }
1239 else if (type == Field::YES) // Old unireg type
1240 regfield->store(ER(ER_YES), strlen(ER(ER_YES)),system_charset_info);
1241 else if (type == Field::NO) // Old unireg type
1242 regfield->store(ER(ER_NO), strlen(ER(ER_NO)),system_charset_info);
1243 else
1244 regfield->reset();
1245 /*
1246 Delete to avoid memory leak for fields that allocate extra
1247 memory (e.g Field_blob::value)
1248 */
1249 delete regfield;
1250 return false;
1251 }
1252
1253
1254 /**
1255 Creates a record buffer consisting of default values for all columns and
1256 stores it in the formfile (.frm file.)
1257
1258 The value stored for each column is
1259
1260 - The default value if the column has one.
1261 - 1 if the column type is @c enum.
1262 - Special messages if the unireg type is YES or NO.
1263 - A buffer full of only zeroes in all other cases. This also happens if the
1264 default is a function.
1265
1266 @param thd The current session.
1267 @param file The .frm file.
1268 @param table_options Describes how to pack the values in the buffer.
1269 @param create_fields A list of column definition objects.
1270 @param reclength Length of the record buffer in bytes.
1271 @param data_offset Offset inside the buffer before the values.
1272 @param handler The storage engine.
1273
1274 @retval true An error occured.
1275 @retval false Success.
1276
1277 */
1278
make_empty_rec(THD * thd,File file,uint table_options,List<Create_field> & create_fields,uint reclength,ulong data_offset,handler * handler)1279 static bool make_empty_rec(THD *thd, File file,
1280 uint table_options,
1281 List<Create_field> &create_fields,
1282 uint reclength,
1283 ulong data_offset,
1284 handler *handler)
1285 {
1286 int error= 0;
1287 uint null_count;
1288 uchar *buff,*null_pos;
1289 TABLE table;
1290 TABLE_SHARE share;
1291 Create_field *field;
1292 enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
1293 bool has_vgc= false;
1294 DBUG_ENTER("make_empty_rec");
1295
1296 /* We need a table to generate columns for default values */
1297 table.s= &share;
1298
1299 if (!(buff=(uchar*) my_malloc(key_memory_frm,
1300 (size_t) reclength,MYF(MY_WME | MY_ZEROFILL))))
1301 {
1302 DBUG_RETURN(1);
1303 }
1304
1305 table.in_use= thd;
1306 table.s->db_low_byte_first= handler->low_byte_first();
1307
1308 null_count=0;
1309 if (!(table_options & HA_OPTION_PACK_RECORD))
1310 {
1311 null_count++; // Need one bit for delete mark
1312 *buff|= 1;
1313 }
1314 null_pos= buff;
1315
1316 List_iterator<Create_field> it(create_fields);
1317 thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values
1318 while ((field=it++))
1319 {
1320 if (field->stored_in_db)
1321 {
1322 /*
1323 Even though Create_field::offset for virtual generated columns already
1324 point at the end of record buffer we still need separate pass for them
1325 in order to allocate null bits from preamble tail as well.
1326 */
1327 if (make_default_value(thd, &table, field, buff + data_offset,
1328 null_pos, &null_count))
1329 {
1330 error= 1;
1331 goto err;
1332 }
1333 }
1334 else
1335 has_vgc= true;
1336 }
1337 if (has_vgc)
1338 {
1339 it.rewind();
1340 while ((field=it++))
1341 {
1342 if (!field->stored_in_db)
1343 {
1344 if (make_default_value(thd, &table, field, buff + data_offset,
1345 null_pos, &null_count))
1346 {
1347 error= 1;
1348 goto err;
1349 }
1350 }
1351 }
1352 }
1353 DBUG_ASSERT(data_offset == ((null_count + 7) / 8));
1354
1355 /*
1356 We need to set the unused bits to 1. If the number of bits is a multiple
1357 of 8 there are no unused bits.
1358 */
1359 if (null_count & 7)
1360 *(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
1361
1362 error= mysql_file_write(file, buff, (size_t) reclength, MYF_RW) != 0;
1363
1364 err:
1365 my_free(buff);
1366 thd->count_cuted_fields= old_count_cuted_fields;
1367 DBUG_RETURN(error);
1368 } /* make_empty_rec */
1369