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