unireg.cc 25.9 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
unknown's avatar
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17 18 19 20
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/*
  Functions to create a unireg form-file from a FIELD and a fieldname-fieldinfo
  struct.
unknown's avatar
unknown committed
21
  In the following functions FIELD * is an ordinary field-structure with
unknown's avatar
unknown committed
22
  the following exeptions:
23
    sc_length,typepos,row,kol,dtype,regnr and field need not to be set.
unknown's avatar
unknown committed
24 25 26 27 28 29
    str is a (long) to record position where 0 is the first position.
*/

#define USES_TYPES
#include "mysql_priv.h"
#include <m_ctype.h>
unknown's avatar
unknown committed
30
#include <assert.h>
unknown's avatar
unknown committed
31

32
#define FCOMP			17		/* Bytes for a packed field */
unknown's avatar
unknown committed
33 34 35

static uchar * pack_screens(List<create_field> &create_fields,
			    uint *info_length, uint *screens, bool small_file);
36 37
static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
                      ulong data_offset);
unknown's avatar
unknown committed
38
static bool pack_header(uchar *forminfo,enum legacy_db_type table_type,
unknown's avatar
unknown committed
39 40
			List<create_field> &create_fields,
			uint info_length, uint screens, uint table_options,
41
			ulong data_offset, handler *file);
unknown's avatar
unknown committed
42 43
static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
			    create_field *last_field);
44 45
static bool pack_fields(File file, List<create_field> &create_fields,
                        ulong data_offset);
unknown's avatar
unknown committed
46
static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type,
unknown's avatar
unknown committed
47 48
			   uint table_options,
			   List<create_field> &create_fields,
49 50
			   uint reclength, ulong data_offset,
                           handler *handler);
unknown's avatar
unknown committed
51

52 53 54 55 56 57
/*
  Create a frm (table definition) file

  SYNOPSIS
    mysql_create_frm()
    thd			Thread handler
unknown's avatar
unknown committed
58
    file_name		Path for file (including database and .frm)
59
    db                  Name of database
unknown's avatar
unknown committed
60
    table               Name of table
61 62 63 64 65
    create_info		create info parameters
    create_fields	Fields to create
    keys		number of keys to create
    key_info		Keys to create
    db_file		Handler to use. May be zero, in which case we use
unknown's avatar
unknown committed
66
			create_info->db_type
67 68 69 70
  RETURN
    0  ok
    1  error
*/
unknown's avatar
unknown committed
71

unknown's avatar
unknown committed
72
bool mysql_create_frm(THD *thd, const char *file_name,
unknown's avatar
unknown committed
73
                      const char *db, const char *table,
74 75 76 77
		      HA_CREATE_INFO *create_info,
		      List<create_field> &create_fields,
		      uint keys, KEY *key_info,
		      handler *db_file)
unknown's avatar
unknown committed
78
{
79
  LEX_STRING str_db_type;
80
  uint reclength,info_length,screens,key_info_length,maxlength,i;
unknown's avatar
unknown committed
81
  ulong key_buff_length;
unknown's avatar
unknown committed
82
  File file;
83
  ulong filepos, data_offset;
unknown's avatar
unknown committed
84 85 86
  uchar fileinfo[64],forminfo[288],*keybuff;
  TYPELIB formnames;
  uchar *screen_buff;
unknown's avatar
unknown committed
87
  char buff[32];
88
#ifdef WITH_PARTITION_STORAGE_ENGINE
unknown's avatar
unknown committed
89
  partition_info *part_info= thd->work_part_info;
90
#endif
91
  DBUG_ENTER("mysql_create_frm");
unknown's avatar
unknown committed
92

93
  DBUG_ASSERT(*fn_rext((char*)file_name)); // Check .frm extension
unknown's avatar
unknown committed
94 95 96
  formnames.type_names=0;
  if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
    DBUG_RETURN(1);
97
  DBUG_ASSERT(db_file != NULL);
98 99 100 101 102 103

 /* If fixed row records, we need one bit to check for deleted rows */
  if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
    create_info->null_bits++;
  data_offset= (create_info->null_bits + 7) / 8;

unknown's avatar
unknown committed
104 105
  if (pack_header(forminfo, ha_legacy_type(create_info->db_type),
                  create_fields,info_length,
106 107
		  screens, create_info->table_options,
                  data_offset, db_file))
unknown's avatar
unknown committed
108 109
  {
    my_free((gptr) screen_buff,MYF(0));
110
    if (thd->net.last_errno != ER_TOO_MANY_FIELDS)
unknown's avatar
unknown committed
111 112 113
      DBUG_RETURN(1);

    // Try again without UNIREG screens (to get more columns)
114
    thd->net.last_error[0]=0;
unknown's avatar
unknown committed
115 116
    if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
      DBUG_RETURN(1);
unknown's avatar
unknown committed
117 118
    if (pack_header(forminfo, ha_legacy_type(create_info->db_type),
                    create_fields,info_length,
119
		    screens, create_info->table_options, data_offset, db_file))
unknown's avatar
unknown committed
120 121 122 123 124 125 126
    {
      my_free((gptr) screen_buff,MYF(0));
      DBUG_RETURN(1);
    }
  }
  reclength=uint2korr(forminfo+266);

127
  /* Calculate extra data segment length */
unknown's avatar
unknown committed
128
  str_db_type.str= (char *) ha_resolve_storage_engine_name(create_info->db_type);
129
  str_db_type.length= strlen(str_db_type.str);
130
  /* str_db_type */
131 132
  create_info->extra_size= (2 + str_db_type.length +
                            2 + create_info->connect_string.length);
133
  /* Partition */
unknown's avatar
unknown committed
134
  create_info->extra_size+= 9;
135
#ifdef WITH_PARTITION_STORAGE_ENGINE
136
  if (part_info)
unknown's avatar
unknown committed
137
  {
138
    create_info->extra_size+= part_info->part_info_len;
unknown's avatar
unknown committed
139
  }
140 141 142 143 144 145 146
#endif

  for (i= 0; i < keys; i++)
  {
    if (key_info[i].parser_name)
      create_info->extra_size+= key_info[i].parser_name->length + 1;
  }
147

unknown's avatar
unknown committed
148
  if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
unknown's avatar
unknown committed
149 150 151 152 153 154
		       create_info, keys)) < 0)
  {
    my_free((gptr) screen_buff,MYF(0));
    DBUG_RETURN(1);
  }

unknown's avatar
unknown committed
155
  key_buff_length= uint4korr(fileinfo+47);
unknown's avatar
unknown committed
156
  keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
157
  key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
unknown's avatar
unknown committed
158 159 160 161 162
  VOID(get_form_pos(file,fileinfo,&formnames));
  if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
    goto err;
  maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
  int2store(forminfo+2,maxlength);
unknown's avatar
unknown committed
163
  int4store(fileinfo+10,(ulong) (filepos+maxlength));
unknown's avatar
unknown committed
164 165 166
  fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
			     (create_info->min_rows == 1) && (keys == 0));
  int2store(fileinfo+28,key_info_length);
167
  strmake((char*) forminfo+47,create_info->comment ? create_info->comment : "",
unknown's avatar
unknown committed
168 169 170
	  60);
  forminfo[46]=(uchar) strlen((char*)forminfo+47);	// Length of comment

171
#ifdef WITH_PARTITION_STORAGE_ENGINE
172
  if (part_info)
unknown's avatar
unknown committed
173
  {
unknown's avatar
unknown committed
174
    fileinfo[61]= (uchar) ha_legacy_type(part_info->default_engine_type);
unknown's avatar
unknown committed
175 176
    DBUG_PRINT("info", ("part_db_type = %d", fileinfo[61]));
  }
177 178
#endif
  int2store(fileinfo+59,db_file->extra_rec_buf_length());
unknown's avatar
unknown committed
179 180 181 182 183 184 185
  if (my_pwrite(file,(byte*) fileinfo,64,0L,MYF_RW) ||
      my_pwrite(file,(byte*) keybuff,key_info_length,
		(ulong) uint2korr(fileinfo+6),MYF_RW))
    goto err;
  VOID(my_seek(file,
	       (ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
	       MY_SEEK_SET,MYF(0)));
unknown's avatar
unknown committed
186 187
  if (make_empty_rec(thd,file,ha_legacy_type(create_info->db_type),
                     create_info->table_options,
188
		     create_fields,reclength, data_offset, db_file))
unknown's avatar
unknown committed
189
    goto err;
190

unknown's avatar
unknown committed
191
  int2store(buff, create_info->connect_string.length);
192
  if (my_write(file, (const byte*)buff, 2, MYF(MY_NABP)) ||
unknown's avatar
unknown committed
193 194
      my_write(file, (const byte*)create_info->connect_string.str,
               create_info->connect_string.length, MYF(MY_NABP)))
195
      goto err;
unknown's avatar
unknown committed
196

197
  int2store(buff, str_db_type.length);
198
  if (my_write(file, (const byte*)buff, 2, MYF(MY_NABP)) ||
199 200 201
      my_write(file, (const byte*)str_db_type.str,
               str_db_type.length, MYF(MY_NABP)))
    goto err;
unknown's avatar
unknown committed
202

203
#ifdef WITH_PARTITION_STORAGE_ENGINE
204 205
  if (part_info)
  {
206 207 208 209
    int4store(buff, part_info->part_info_len);
    if (my_write(file, (const byte*)buff, 4, MYF_RW) ||
        my_write(file, (const byte*)part_info->part_info_string,
                 part_info->part_info_len + 1, MYF_RW))
210 211
      goto err;
  }
212
  else
213
#endif
214
  {
unknown's avatar
unknown committed
215 216
    bzero(buff, 9);
    if (my_write(file, (byte*) buff, 9, MYF_RW))
217 218 219 220 221 222 223 224 225 226 227
      goto err;
  }
  for (i= 0; i < keys; i++)
  {
    if (key_info[i].parser_name)
    {
      if (my_write(file, (const byte*)key_info[i].parser_name->str,
                   key_info[i].parser_name->length + 1, MYF(MY_NABP)))
        goto err;
    }
  }
unknown's avatar
unknown committed
228

229 230 231 232 233 234
  VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
  if (my_write(file,(byte*) forminfo,288,MYF_RW) ||
      my_write(file,(byte*) screen_buff,info_length,MYF_RW) ||
      pack_fields(file, create_fields, data_offset))
    goto err;

unknown's avatar
unknown committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
#ifdef HAVE_CRYPTED_FRM
  if (create_info->password)
  {
    char tmp=2,*disk_buff=0;
    SQL_CRYPT *crypted=new SQL_CRYPT(create_info->password);
    if (!crypted || my_pwrite(file,&tmp,1,26,MYF_RW))	// Mark crypted
      goto err;
    uint read_length=uint2korr(forminfo)-256;
    VOID(my_seek(file,filepos+256,MY_SEEK_SET,MYF(0)));
    if (read_string(file,(gptr*) &disk_buff,read_length))
      goto err;
    crypted->encode(disk_buff,read_length);
    delete crypted;
    if (my_pwrite(file,disk_buff,read_length,filepos+256,MYF_RW))
    {
      my_free(disk_buff,MYF(0));
      goto err;
    }
    my_free(disk_buff,MYF(0));
  }
#endif

  my_free((gptr) screen_buff,MYF(0));
unknown's avatar
unknown committed
258
  my_free((gptr) keybuff, MYF(0));
259 260 261

  if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
      my_sync(file, MYF(MY_WME)))
unknown's avatar
unknown committed
262
    goto err2;
263
  if (my_close(file,MYF(MY_WME)))
264
    goto err3;
265 266 267 268 269 270 271 272 273 274 275

  {
    /* Unescape all UCS2 intervals: were escaped in pack_headers */
    List_iterator<create_field> it(create_fields);
    create_field *field;
    while ((field=it++))
    {
      if (field->interval && field->charset->mbminlen > 1)
        unhex_type2(field->interval);
    }
  }
unknown's avatar
unknown committed
276 277 278 279
  DBUG_RETURN(0);

err:
  my_free((gptr) screen_buff,MYF(0));
unknown's avatar
unknown committed
280
  my_free((gptr) keybuff, MYF(0));
281
err2:
unknown's avatar
unknown committed
282
  VOID(my_close(file,MYF(MY_WME)));
283
err3:
284
  my_delete(file_name,MYF(0));
285 286 287
  DBUG_RETURN(1);
} /* mysql_create_frm */

288 289 290 291 292

/*
  Create a frm (table definition) file and the tables

  SYNOPSIS
293
    rea_create_table()
294
    thd			Thread handler
295
    path		Name of file (including database, without .frm)
unknown's avatar
unknown committed
296 297
    db			Data base name
    table_name		Table name
298 299 300 301
    create_info		create info parameters
    create_fields	Fields to create
    keys		number of keys to create
    key_info		Keys to create
unknown's avatar
unknown committed
302 303
    file		Handler to use

304 305 306 307 308
  RETURN
    0  ok
    1  error
*/

unknown's avatar
unknown committed
309 310 311 312 313
int 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)
314 315 316
{
  DBUG_ENTER("rea_create_table");

317 318 319
  char frm_name[FN_REFLEN];
  strxmov(frm_name, path, reg_ext, NullS);
  if (mysql_create_frm(thd, frm_name, db, table_name, create_info,
320
                       create_fields, keys, key_info, file))
321

322
    DBUG_RETURN(1);
323 324 325

  // Make sure mysql_create_frm din't remove extension
  DBUG_ASSERT(*fn_rext(frm_name));
326
  if (file->create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info))
327
    goto err_handler;
unknown's avatar
unknown committed
328 329
  if (!create_info->frm_only && ha_create_table(thd, path, db, table_name,
                                                create_info,0))
330
    goto err_handler;
331
  DBUG_RETURN(0);
unknown's avatar
unknown committed
332

333
err_handler:
334
  my_delete(frm_name, MYF(0));
335
  DBUG_RETURN(1);
unknown's avatar
unknown committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
} /* rea_create_table */


	/* Pack screens to a screen for save in a form-file */

static uchar * pack_screens(List<create_field> &create_fields,
			    uint *info_length, uint *screens,
			    bool small_file)
{
  reg1 uint i;
  uint row,start_row,end_row,fields_on_screen;
  uint length,cols;
  uchar *info,*pos,*start_screen;
  uint fields=create_fields.elements;
  List_iterator<create_field> it(create_fields);
  DBUG_ENTER("pack_screens");

  start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;

  *screens=(fields-1)/fields_on_screen+1;
  length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);

  create_field *field;
  while ((field=it++))
unknown's avatar
unknown committed
360
    length+=(uint) strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
unknown's avatar
unknown committed
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389

  if (!(info=(uchar*) my_malloc(length,MYF(MY_WME))))
    DBUG_RETURN(0);

  start_screen=0;
  row=end_row;
  pos=info;
  it.rewind();
  for (i=0 ; i < fields ; i++)
  {
    create_field *cfield=it++;
    if (row++ == end_row)
    {
      if (i)
      {
	length=(uint) (pos-start_screen);
	int2store(start_screen,length);
	start_screen[2]=(uchar) (fields_on_screen+1);
	start_screen[3]=(uchar) (fields_on_screen);
      }
      row=start_row;
      start_screen=pos;
      pos+=4;
      pos[0]= (uchar) start_row-2;	/* Header string */
      pos[1]= (uchar) (cols >> 2);
      pos[2]= (uchar) (cols >> 1) +1;
      strfill((my_string) pos+3,(uint) (cols >> 1),' ');
      pos+=(cols >> 1)+4;
    }
unknown's avatar
unknown committed
390
    length=(uint) strlen(cfield->field_name);
unknown's avatar
unknown committed
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
    if (length > cols-3)
      length=cols-3;

    if (!small_file)
    {
      pos[0]=(uchar) row;
      pos[1]=0;
      pos[2]=(uchar) (length+1);
      pos=(uchar*) strmake((char*) pos+3,cfield->field_name,length)+1;
    }
    cfield->row=(uint8) row;
    cfield->col=(uint8) (length+1);
    cfield->sc_length=(uint8) min(cfield->length,cols-(length+2));
  }
  length=(uint) (pos-start_screen);
  int2store(start_screen,length);
  start_screen[2]=(uchar) (row-start_row+2);
  start_screen[3]=(uchar) (row-start_row+1);

  *info_length=(uint) (pos-info);
  DBUG_RETURN(info);
} /* pack_screens */


	/* Pack keyinfo and keynames to keybuff for save in form-file. */

417 418
static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
                      ulong data_offset)
unknown's avatar
unknown committed
419 420
{
  uint key_parts,length;
unknown's avatar
unknown committed
421
  uchar *pos, *keyname_pos;
unknown's avatar
unknown committed
422 423 424 425 426 427 428 429
  KEY *key,*end;
  KEY_PART_INFO *key_part,*key_part_end;
  DBUG_ENTER("pack_keys");

  pos=keybuff+6;
  key_parts=0;
  for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
  {
430 431 432 433
    int2store(pos, (key->flags ^ HA_NOSAME));
    int2store(pos+2,key->key_length);
    pos[4]= (uchar) key->key_parts;
    pos[5]= (uchar) key->algorithm;
unknown's avatar
unknown committed
434
    pos[6]=pos[7]=0;				// For the future
435
    pos+=8;
unknown's avatar
unknown committed
436
    key_parts+=key->key_parts;
437
    DBUG_PRINT("loop",("flags: %d  key_parts: %d at 0x%lx",
unknown's avatar
unknown committed
438 439 440 441 442 443 444
		       key->flags,key->key_parts,
		       key->key_part));
    for (key_part=key->key_part,key_part_end=key_part+key->key_parts ;
	 key_part != key_part_end ;
	 key_part++)

    {
445 446 447 448
      uint offset;
      DBUG_PRINT("loop",("field: %d  startpos: %lu  length: %ld",
			 key_part->fieldnr, key_part->offset + data_offset,
                         key_part->length));
unknown's avatar
unknown committed
449
      int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
450 451
      offset= (uint) (key_part->offset+data_offset+1);
      int2store(pos+2, offset);
unknown's avatar
unknown committed
452 453 454 455 456 457 458 459
      pos[4]=0;					// Sort order
      int2store(pos+5,key_part->key_type);
      int2store(pos+7,key_part->length);
      pos+=9;
    }
  }
	/* Save keynames */
  keyname_pos=pos;
460
  *pos++=(uchar) NAMES_SEP_CHAR;
unknown's avatar
unknown committed
461 462 463
  for (key=keyinfo ; key != end ; key++)
  {
    uchar *tmp=(uchar*) strmov((char*) pos,key->name);
464
    *tmp++= (uchar) NAMES_SEP_CHAR;
unknown's avatar
unknown committed
465 466 467 468 469
    *tmp=0;
    pos=tmp;
  }
  *(pos++)=0;

unknown's avatar
unknown committed
470 471
  if (key_count > 127 || key_parts > 127)
  {
unknown's avatar
unknown committed
472 473
    keybuff[0]= (key_count & 0x7f) | 0x80;
    keybuff[1]= key_count >> 7;
unknown's avatar
unknown committed
474 475 476 477 478 479
    int2store(keybuff+2,key_parts);
  }
  else
  {
    keybuff[0]=(uchar) key_count;
    keybuff[1]=(uchar) key_parts;
480
    keybuff[2]= keybuff[3]= 0;
unknown's avatar
unknown committed
481
  }
unknown's avatar
unknown committed
482
  length=(uint) (pos-keyname_pos);
unknown's avatar
unknown committed
483 484 485 486 487 488 489
  int2store(keybuff+4,length);
  DBUG_RETURN((uint) (pos-keybuff));
} /* pack_keys */


	/* Make formheader */

unknown's avatar
unknown committed
490
static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
unknown's avatar
unknown committed
491
			List<create_field> &create_fields,
492 493
                        uint info_length, uint screens, uint table_options,
                        ulong data_offset, handler *file)
unknown's avatar
unknown committed
494
{
495
  uint length,int_count,int_length,no_empty, int_parts;
unknown's avatar
unknown committed
496 497
  uint time_stamp_pos,null_fields;
  ulong reclength, totlength, n_length, com_length;
unknown's avatar
unknown committed
498 499 500 501
  DBUG_ENTER("pack_header");

  if (create_fields.elements > MAX_FIELDS)
  {
unknown's avatar
unknown committed
502
    my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
unknown's avatar
unknown committed
503 504 505
    DBUG_RETURN(1);
  }

unknown's avatar
unknown committed
506 507
  totlength= 0L;
  reclength= data_offset;
508 509
  no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=
    com_length=0;
unknown's avatar
unknown committed
510 511 512 513 514 515 516 517 518
  n_length=2L;

	/* Check fields */

  List_iterator<create_field> it(create_fields);
  create_field *field;
  while ((field=it++))
  {
    totlength+= field->length;
519
    com_length+= field->comment.length;
unknown's avatar
unknown committed
520 521 522 523 524 525 526
    if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY ||
	field->unireg_check & MTYP_NOEMPTY_BIT)
    {
      field->unireg_check= (Field::utype) ((uint) field->unireg_check |
					   MTYP_NOEMPTY_BIT);
      no_empty++;
    }
527 528 529 530 531 532
    /* 
      We mark first TIMESTAMP field with NOW() in DEFAULT or ON UPDATE 
      as auto-update field.
    */
    if (field->sql_type == FIELD_TYPE_TIMESTAMP &&
        MTYP_TYPENR(field->unireg_check) != Field::NONE &&
unknown's avatar
unknown committed
533
	!time_stamp_pos)
534
      time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
unknown's avatar
unknown committed
535
    length=field->pack_length;
unknown's avatar
unknown committed
536 537
    /* Ensure we don't have any bugs when generating offsets */
    DBUG_ASSERT(reclength == field->offset + data_offset);
538 539
    if ((uint) field->offset+ (uint) data_offset+ length > reclength)
      reclength=(uint) (field->offset+ data_offset + length);
unknown's avatar
unknown committed
540 541 542 543 544
    n_length+= (ulong) strlen(field->field_name)+1;
    field->interval_id=0;
    if (field->interval)
    {
      uint old_int_count=int_count;
545 546 547 548 549 550 551 552 553 554 555 556

      if (field->charset->mbminlen > 1)
      {
        /* Escape UCS2 intervals using HEX notation */
        for (uint pos= 0; pos < field->interval->count; pos++)
        {
          char *dst;
          uint length= field->interval->type_lengths[pos], hex_length;
          const char *src= field->interval->type_names[pos];
          hex_length= length * 2;
          field->interval->type_lengths[pos]= hex_length;
          field->interval->type_names[pos]= dst= sql_alloc(hex_length + 1);
unknown's avatar
unknown committed
557
          octet2hex(dst, src, length);
558 559 560
        }
      }

unknown's avatar
unknown committed
561 562 563 564
      field->interval_id=get_interval_id(&int_count,create_fields,field);
      if (old_int_count != int_count)
      {
	for (const char **pos=field->interval->type_names ; *pos ; pos++)
unknown's avatar
unknown committed
565
	  int_length+=(uint) strlen(*pos)+1;	// field + suffix prefix
unknown's avatar
unknown committed
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
	int_parts+=field->interval->count+1;
      }
    }
    if (f_maybe_null(field->pack_flag))
      null_fields++;
  }
  int_length+=int_count*2;			// 255 prefix + 0 suffix

	/* Save values in forminfo */

  if (reclength > (ulong) file->max_record_length())
  {
    my_error(ER_TOO_BIG_ROWSIZE, MYF(0), (uint) file->max_record_length());
    DBUG_RETURN(1);
  }
  /* Hack to avoid bugs with small static rows in MySQL */
  reclength=max(file->min_record_length(table_options),reclength);
  if (info_length+(ulong) create_fields.elements*FCOMP+288+
584
      n_length+int_length+com_length > 65535L || int_count > 255)
unknown's avatar
unknown committed
585
  {
unknown's avatar
unknown committed
586
    my_message(ER_TOO_MANY_FIELDS, ER(ER_TOO_MANY_FIELDS), MYF(0));
unknown's avatar
unknown committed
587 588 589 590
    DBUG_RETURN(1);
  }

  bzero((char*)forminfo,288);
591 592
  length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+
	  com_length);
unknown's avatar
unknown committed
593 594 595 596 597 598 599 600 601 602 603 604
  int2store(forminfo,length);
  forminfo[256] = (uint8) screens;
  int2store(forminfo+258,create_fields.elements);
  int2store(forminfo+260,info_length);
  int2store(forminfo+262,totlength);
  int2store(forminfo+264,no_empty);
  int2store(forminfo+266,reclength);
  int2store(forminfo+268,n_length);
  int2store(forminfo+270,int_count);
  int2store(forminfo+272,int_parts);
  int2store(forminfo+274,int_length);
  int2store(forminfo+276,time_stamp_pos);
605 606
  int2store(forminfo+278,80);			/* Columns needed */
  int2store(forminfo+280,22);			/* Rows needed */
unknown's avatar
unknown committed
607
  int2store(forminfo+282,null_fields);
608
  int2store(forminfo+284,com_length);
unknown's avatar
unknown committed
609
  /* Up to forminfo+288 is free to use for additional information */
unknown's avatar
unknown committed
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
  DBUG_RETURN(0);
} /* pack_header */


	/* get each unique interval each own id */

static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
			    create_field *last_field)
{
  List_iterator<create_field> it(create_fields);
  create_field *field;
  TYPELIB *interval=last_field->interval;

  while ((field=it++) != last_field)
  {
    if (field->interval_id && field->interval->count == interval->count)
    {
      const char **a,**b;
      for (a=field->interval->type_names, b=interval->type_names ;
	   *a && !strcmp(*a,*b);
	   a++,b++) ;

      if (! *a)
      {
	return field->interval_id;		// Re-use last interval
      }
    }
  }
  return ++*int_count;				// New unique interval
}


	/* Save fields, fieldnames and intervals */

644 645
static bool pack_fields(File file, List<create_field> &create_fields,
                        ulong data_offset)
unknown's avatar
unknown committed
646 647
{
  reg2 uint i;
648
  uint int_count, comment_length=0;
unknown's avatar
unknown committed
649 650 651 652 653 654 655 656 657 658 659
  uchar buff[MAX_FIELD_WIDTH];
  create_field *field;
  DBUG_ENTER("pack_fields");

	/* Write field info */

  List_iterator<create_field> it(create_fields);

  int_count=0;
  while ((field=it++))
  {
660
    uint recpos;
unknown's avatar
unknown committed
661 662 663
    buff[0]= (uchar) field->row;
    buff[1]= (uchar) field->col;
    buff[2]= (uchar) field->sc_length;
664
    int2store(buff+3, field->length);
665 666
    /* The +1 is here becasue the col offset in .frm file have offset 1 */
    recpos= field->offset+1 + (uint) data_offset;
667 668 669 670 671
    int3store(buff+5,recpos);
    int2store(buff+8,field->pack_flag);
    int2store(buff+10,field->unireg_check);
    buff[12]= (uchar) field->interval_id;
    buff[13]= (uchar) field->sql_type; 
unknown's avatar
unknown committed
672
    if (field->sql_type == FIELD_TYPE_GEOMETRY)
unknown's avatar
SCRUM:  
unknown committed
673
    {
unknown's avatar
unknown committed
674
      buff[14]= (uchar) field->geom_type;
unknown's avatar
SCRUM:  
unknown committed
675 676 677 678
#ifndef HAVE_SPATIAL
      DBUG_ASSERT(0);                           // Should newer happen
#endif
    }
679
    else if (field->charset) 
unknown's avatar
unknown committed
680
      buff[14]= (uchar) field->charset->number;
681 682
    else
      buff[14]= 0;				// Numerical
683
    int2store(buff+15, field->comment.length);
684
    comment_length+= field->comment.length;
unknown's avatar
unknown committed
685 686 687 688 689 690
    set_if_bigger(int_count,field->interval_id);
    if (my_write(file,(byte*) buff,FCOMP,MYF_RW))
      DBUG_RETURN(1);
  }

	/* Write fieldnames */
691
  buff[0]=(uchar) NAMES_SEP_CHAR;
unknown's avatar
unknown committed
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
  if (my_write(file,(byte*) buff,1,MYF_RW))
    DBUG_RETURN(1);
  i=0;
  it.rewind();
  while ((field=it++))
  {
    char *pos= strmov((char*) buff,field->field_name);
    *pos++=NAMES_SEP_CHAR;
    if (i == create_fields.elements-1)
      *pos++=0;
    if (my_write(file,(byte*) buff,(uint) (pos-(char*) buff),MYF_RW))
      DBUG_RETURN(1);
    i++;
  }

	/* Write intervals */
  if (int_count)
  {
710
    String tmp((char*) buff,sizeof(buff), &my_charset_bin);
unknown's avatar
unknown committed
711 712 713 714 715 716 717 718
    tmp.length(0);
    it.rewind();
    int_count=0;
    while ((field=it++))
    {
      if (field->interval_id > int_count)
      {
	int_count=field->interval_id;
719
	tmp.append(NAMES_SEP_CHAR);
unknown's avatar
unknown committed
720 721 722
	for (const char **pos=field->interval->type_names ; *pos ; pos++)
	{
	  tmp.append(*pos);
723
	  tmp.append(NAMES_SEP_CHAR);
unknown's avatar
unknown committed
724 725 726 727 728 729 730
	}
	tmp.append('\0');			// End of intervall
      }
    }
    if (my_write(file,(byte*) tmp.ptr(),tmp.length(),MYF_RW))
      DBUG_RETURN(1);
  }
731 732 733 734 735 736 737 738 739 740 741 742
  if (comment_length)
  {
    it.rewind();
    int_count=0;
    while ((field=it++))
    {
      if (field->comment.length)
	if (my_write(file, (byte*) field->comment.str, field->comment.length,
		     MYF_RW))
	  DBUG_RETURN(1);
    }
  }
unknown's avatar
unknown committed
743 744 745 746
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
747
	/* save an empty record on start of formfile */
unknown's avatar
unknown committed
748

unknown's avatar
unknown committed
749
static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
unknown's avatar
unknown committed
750 751
			   uint table_options,
			   List<create_field> &create_fields,
unknown's avatar
unknown committed
752
			   uint reclength,
753 754
                           ulong data_offset,
                           handler *handler)
unknown's avatar
unknown committed
755
{
unknown's avatar
unknown committed
756
  int error= 0;
unknown's avatar
unknown committed
757
  Field::utype type;
unknown's avatar
unknown committed
758
  uint null_count;
unknown's avatar
unknown committed
759 760
  uchar *buff,*null_pos;
  TABLE table;
unknown's avatar
unknown committed
761
  TABLE_SHARE share;
unknown's avatar
unknown committed
762
  create_field *field;
763
  enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
unknown's avatar
unknown committed
764 765 766
  DBUG_ENTER("make_empty_rec");

  /* We need a table to generate columns for default values */
unknown's avatar
unknown committed
767 768 769
  bzero((char*) &table, sizeof(table));
  bzero((char*) &share, sizeof(share));
  table.s= &share;
unknown's avatar
unknown committed
770

771
  if (!(buff=(uchar*) my_malloc((uint) reclength,MYF(MY_WME | MY_ZEROFILL))))
772
  {
unknown's avatar
unknown committed
773
    DBUG_RETURN(1);
774 775
  }

776
  table.in_use= thd;
777 778
  table.s->db_low_byte_first= handler->low_byte_first();
  table.s->blob_ptr_size= portable_sizeof_char_ptr;
779

unknown's avatar
unknown committed
780 781 782
  null_count=0;
  if (!(table_options & HA_OPTION_PACK_RECORD))
  {
783
    null_count++;			// Need one bit for delete mark
784
    *buff|= 1;
unknown's avatar
unknown committed
785
  }
786
  null_pos= buff;
unknown's avatar
unknown committed
787 788

  List_iterator<create_field> it(create_fields);
789
  thd->count_cuted_fields= CHECK_FIELD_WARN;    // To find wrong default values
unknown's avatar
unknown committed
790 791
  while ((field=it++))
  {
792 793 794
    /*
      regfield don't have to be deleted as it's allocated with sql_alloc()
    */
unknown's avatar
unknown committed
795 796 797 798 799 800 801 802 803 804 805 806
    Field *regfield= make_field(&share,
                                (char*) buff+field->offset + data_offset,
                                field->length,
                                null_pos + null_count / 8,
                                null_count & 7,
                                field->pack_flag,
                                field->sql_type,
                                field->charset,
                                field->geom_type,
                                field->unireg_check,
                                field->interval,
                                field->field_name);
807 808
    if (!regfield)
      goto err;                                 // End of memory
809

unknown's avatar
unknown committed
810 811 812
    /* save_in_field() will access regfield->table->in_use */
    regfield->init(&table);

unknown's avatar
unknown committed
813
    if (!(field->flags & NOT_NULL_FLAG))
814 815
    {
      *regfield->null_ptr|= regfield->null_bit;
unknown's avatar
unknown committed
816
      null_count++;
817
    }
unknown's avatar
unknown committed
818

819 820
    if (field->sql_type == FIELD_TYPE_BIT && !f_bit_as_char(field->pack_flag))
      null_count+= field->length & 7;
unknown's avatar
unknown committed
821 822 823 824 825 826

    type= (Field::utype) MTYP_TYPENR(field->unireg_check);

    if (field->def &&
	(regfield->real_type() != FIELD_TYPE_YEAR ||
	 field->def->val_int() != 0))
827 828 829 830 831
    {
      if (field->def->save_in_field(regfield, 1))
      {
        my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name);
        error= 1;
832
        delete regfield; //To avoid memory leak
833 834 835
        goto err;
      }
    }
unknown's avatar
unknown committed
836 837 838 839
    else if (regfield->real_type() == FIELD_TYPE_ENUM &&
	     (field->flags & NOT_NULL_FLAG))
    {
      regfield->set_notnull();
840
      regfield->store((longlong) 1, TRUE);
unknown's avatar
unknown committed
841 842
    }
    else if (type == Field::YES)		// Old unireg type
843
      regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)),system_charset_info);
unknown's avatar
unknown committed
844
    else if (type == Field::NO)			// Old unireg type
845
      regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),system_charset_info);
unknown's avatar
unknown committed
846 847 848
    else
      regfield->reset();
  }
unknown's avatar
unknown committed
849
  DBUG_ASSERT(data_offset == ((null_count + 7) / 8));
850

851 852 853 854 855
  /*
    We need to set the unused bits to 1. If the number of bits is a multiple
    of 8 there are no unused bits.
  */
  if (null_count & 7)
856 857
    *(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);

858
  error=(int) my_write(file,(byte*) buff, (uint) reclength,MYF_RW);
859 860

err:
unknown's avatar
unknown committed
861
  my_free((gptr) buff,MYF(MY_FAE));
862
  thd->count_cuted_fields= old_count_cuted_fields;
unknown's avatar
unknown committed
863 864
  DBUG_RETURN(error);
} /* make_empty_rec */