Commit 9ec326a8 authored by Sergei Golubchik's avatar Sergei Golubchik

cleanup frm creation:

* comments
* cosmetic changes, *(ptr+5) -> ptr[5]
* a couple of trivial functions -> inline
* remove unused argument from pack_header()
* create_frm() no longer creates frm file (the function used to prepare and
  fill a memory buffer and call my_create at the end. Now it only prepares
  a memory buffer). Renamed accordingly.
* don't call pack_screen twice, go for a smaller screen area in the first attempt
* remove useless calls to check_duplicate_warning()
* don't write unireg screens to .frm files
* remove make_new_entry(), it's basically dead code, always calculating
  and writing into frm the same string value. replace the function call
  with the constant string.
parent 84b88217
......@@ -12701,12 +12701,12 @@ CREATE TABLE t1(a INT, b BLOB) ENGINE=archive;
SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM
INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
DATA_LENGTH AVG_ROW_LENGTH
8666 15
8608 15
INSERT INTO t1 VALUES(1, 'sampleblob1'),(2, 'sampleblob2');
SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM
INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
DATA_LENGTH AVG_ROW_LENGTH
8700 4350
8642 4321
DROP TABLE t1;
SET @save_join_buffer_size= @@join_buffer_size;
SET @@join_buffer_size= 8192;
......
......@@ -15,10 +15,10 @@ ENGINE = ARCHIVE;
INSERT INTO t1 VALUES(CURRENT_DATE);
SELECT DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
DATA_LENGTH INDEX_LENGTH
8658 0
8604 0
SELECT DATA_LENGTH, INDEX_LENGTH FROM information_schema.TABLES WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
DATA_LENGTH INDEX_LENGTH
8658 0
8604 0
DROP TABLE t1;
drop database if exists db99;
drop table if exists t1;
......
......@@ -2383,7 +2383,7 @@ class Create_field :public Sql_alloc
/** structure with parsed options (for comparing fields in ALTER TABLE) */
ha_field_option_struct *option_struct;
uint8 row,col,sc_length,interval_id; // For rea_create_table
uint8 interval_id; // For rea_create_table
uint offset,pack_flag;
/*
......
......@@ -594,7 +594,7 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
File file;
MY_STAT stats;
uchar *buf;
uchar head[64];
uchar head[FRM_HEADER_SIZE];
char path[FN_REFLEN];
DBUG_ENTER("open_table_def");
DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", share->db.str,
......@@ -690,6 +690,10 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
28..29 (used to be key_info_length)
They're still set, for compatibility reasons, but never read.
42..46 are unused since 5.0 (were for RAID support)
Also, there're few unused bytes in forminfo.
*/
bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, const char *path,
......@@ -739,7 +743,7 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, const char *path,
if (path && writefrm(path, frm_image, frm_length))
goto err;
if (frm_length < 64 + 288)
if (frm_length < FRM_HEADER_SIZE + FRM_FORMINFO_SIZE)
goto err;
new_field_pack_flag= frm_image[27];
......@@ -748,11 +752,12 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, const char *path,
/* Position of the form in the form file. */
len = uint2korr(frm_image+4);
if (frm_length < 64 + len || !(pos= uint4korr(frm_image + 64 + len)))
if (frm_length < FRM_HEADER_SIZE + len ||
!(pos= uint4korr(frm_image + FRM_HEADER_SIZE + len)))
goto err;
forminfo= frm_image + pos;
if (forminfo + 288 >= frm_image_end)
if (forminfo + FRM_FORMINFO_SIZE >= frm_image_end)
goto err;
share->frm_version= frm_image[2];
......@@ -766,13 +771,13 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, const char *path,
share->frm_version= FRM_VER_TRUE_VARCHAR;
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (*(frm_image+61) &&
if (frm_image[61] &&
!(share->default_part_db_type=
ha_checktype(thd, (enum legacy_db_type) (uint) *(frm_image+61), 1, 0)))
ha_checktype(thd, (enum legacy_db_type) (uint) frm_image[61], 1, 0)))
goto err;
DBUG_PRINT("info", ("default_part_db_type = %u", frm_image[61]));
#endif
legacy_db_type= (enum legacy_db_type) (uint) *(frm_image+3);
legacy_db_type= (enum legacy_db_type) (uint) frm_image[3];
DBUG_ASSERT(share->db_plugin == NULL);
/*
if the storage engine is dynamic, no point in resolving it by its
......@@ -1004,7 +1009,7 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, const char *path,
share->reclength = uint2korr((frm_image+16));
share->stored_rec_length= share->reclength;
if (*(frm_image+26) == 1)
if (frm_image[26] == 1)
share->system= 1; /* one-record-database */
record_offset= (ulong) (uint2korr(frm_image+6)+
......@@ -1196,7 +1201,7 @@ bool TABLE_SHARE::init_from_binary_frm_image(THD *thd, const char *path,
share->default_values= record;
memcpy(record, frm_image + record_offset, share->reclength);
disk_buff= frm_image + pos + 288;
disk_buff= frm_image + pos + FRM_FORMINFO_SIZE;
share->fields= uint2korr(forminfo+258);
pos= uint2korr(forminfo+260); /* Length of all screens */
......@@ -2705,79 +2710,7 @@ void free_field_buffers_larger_than(TABLE *table, uint32 size)
}
}
/* Add a new form to a form file */
ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
const char *newname)
{
uint i,bufflength,maxlength,n_length,length,names;
ulong endpos,newpos;
uchar buff[IO_SIZE];
uchar *pos;
DBUG_ENTER("make_new_entry");
length=(uint) strlen(newname)+1;
n_length=uint2korr(fileinfo+4);
maxlength=uint2korr(fileinfo+6);
names=uint2korr(fileinfo+8);
newpos=uint4korr(fileinfo+10);
if (64+length+n_length+(names+1)*4 > maxlength)
{ /* Expand file */
newpos+=IO_SIZE;
int4store(fileinfo+10,newpos);
/* Copy from file-end */
endpos= (ulong) mysql_file_seek(file, 0L, MY_SEEK_END, MYF(0));
bufflength= (uint) (endpos & (IO_SIZE-1)); /* IO_SIZE is a power of 2 */
while (endpos > maxlength)
{
mysql_file_seek(file, (ulong) (endpos-bufflength), MY_SEEK_SET, MYF(0));
if (mysql_file_read(file, buff, bufflength, MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L);
mysql_file_seek(file, (ulong) (endpos-bufflength+IO_SIZE), MY_SEEK_SET,
MYF(0));
if ((mysql_file_write(file, buff, bufflength, MYF(MY_NABP+MY_WME))))
DBUG_RETURN(0);
endpos-=bufflength; bufflength=IO_SIZE;
}
bzero(buff,IO_SIZE); /* Null new block */
mysql_file_seek(file, (ulong) maxlength, MY_SEEK_SET, MYF(0));
if (mysql_file_write(file, buff, bufflength, MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L);
maxlength+=IO_SIZE; /* Fix old ref */
int2store(fileinfo+6,maxlength);
for (i=names, pos= (uchar*) *formnames->type_names+n_length-1; i-- ;
pos+=4)
{
endpos=uint4korr(pos)+IO_SIZE;
int4store(pos,endpos);
}
}
if (n_length == 1 )
{ /* First name */
length++;
(void) strxmov((char*) buff,"/",newname,"/",NullS);
}
else
(void) strxmov((char*) buff,newname,"/",NullS); /* purecov: inspected */
mysql_file_seek(file, 63L+(ulong) n_length, MY_SEEK_SET, MYF(0));
if (mysql_file_write(file, buff, (size_t) length+1, MYF(MY_NABP+MY_WME)) ||
(names && mysql_file_write(file,
(uchar*) (*formnames->type_names+n_length-1),
names*4, MYF(MY_NABP+MY_WME))) ||
mysql_file_write(file, fileinfo+10, 4, MYF(MY_NABP+MY_WME)))
DBUG_RETURN(0L); /* purecov: inspected */
int2store(fileinfo+8,names+1);
int2store(fileinfo+4,n_length+length);
(void) mysql_file_chsize(file, newpos, 0, MYF(MY_WME));/* Append file with '\0' */
DBUG_RETURN(newpos);
} /* make_new_entry */
/* error message when opening a form file */
/* error message when opening a form file */
void open_table_error(TABLE_SHARE *share, enum open_frm_error error,
int db_errno)
......@@ -2928,28 +2861,6 @@ static uint find_field(Field **fields, uchar *record, uint start, uint length)
}
/* Check that the integer is in the internal */
int set_zone(register int nr, int min_zone, int max_zone)
{
if (nr<=min_zone)
return (min_zone);
if (nr>=max_zone)
return (max_zone);
return (nr);
} /* set_zone */
/* Adjust number to next larger disk buffer */
ulong next_io_size(register ulong pos)
{
reg2 ulong offset;
if ((offset= pos & (IO_SIZE-1)))
return pos-offset+IO_SIZE;
return pos;
} /* next_io_size */
/*
Store an SQL quoted string.
......@@ -3012,22 +2923,13 @@ void append_unescaped(String *res, const char *pos, uint length)
}
/* Create a .frm file */
File create_frm(THD *thd, const char *name, const char *db,
const char *table, uint reclength, uchar *fileinfo,
HA_CREATE_INFO *create_info, uint keys, KEY *key_info)
void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo,
HA_CREATE_INFO *create_info, uint keys, KEY *key_info)
{
register File file;
ulong length;
uchar fill[IO_SIZE];
int create_flags= O_RDWR | O_TRUNC;
ulong key_comment_total_bytes= 0;
uint i;
DBUG_ENTER("create_frm");
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags|= O_EXCL | O_NOFOLLOW;
DBUG_ENTER("prepare_frm_header");
/* Fix this when we have new .frm files; Current limit is 4G rows (TODO) */
if (create_info->max_rows > UINT_MAX32)
......@@ -3035,101 +2937,81 @@ File create_frm(THD *thd, const char *name, const char *db,
if (create_info->min_rows > UINT_MAX32)
create_info->min_rows= UINT_MAX32;
if ((file= mysql_file_create(key_file_frm,
name, CREATE_MODE, create_flags, MYF(0))) >= 0)
{
uint key_length, tmp_key_length, tmp, csid;
bzero((char*) fileinfo,64);
/* header */
fileinfo[0]=(uchar) 254;
fileinfo[1]= 1;
fileinfo[2]= FRM_VER+3+ test(create_info->varchar);
fileinfo[3]= (uchar) ha_legacy_type(
ha_checktype(thd,ha_legacy_type(create_info->db_type),0,0));
fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
/*
Keep in sync with pack_keys() in unireg.cc
For each key:
8 bytes for the key header
9 bytes for each key-part (MAX_REF_PARTS)
NAME_LEN bytes for the name
1 byte for the NAMES_SEP_CHAR (before the name)
For all keys:
6 bytes for the header
1 byte for the NAMES_SEP_CHAR (after the last name)
9 extra bytes (padding for safety? alignment?)
*/
for (i= 0; i < keys; i++)
{
DBUG_ASSERT(test(key_info[i].flags & HA_USES_COMMENT) ==
(key_info[i].comment.length > 0));
if (key_info[i].flags & HA_USES_COMMENT)
key_comment_total_bytes += 2 + key_info[i].comment.length;
}
key_length= keys * (8 + MAX_REF_PARTS * 9 + NAME_LEN + 1) + 16
+ key_comment_total_bytes;
length= next_io_size((ulong) (IO_SIZE+key_length+reclength+
create_info->extra_size));
int4store(fileinfo+10,length);
tmp_key_length= (key_length < 0xffff) ? key_length : 0xffff;
int2store(fileinfo+14,tmp_key_length);
int2store(fileinfo+16,reclength);
int4store(fileinfo+18,create_info->max_rows);
int4store(fileinfo+22,create_info->min_rows);
/* fileinfo[26] is set in mysql_create_frm() */
fileinfo[27]=2; // Use long pack-fields
/* fileinfo[28 & 29] is set to key_info_length in mysql_create_frm() */
create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
int2store(fileinfo+30,create_info->table_options);
fileinfo[32]=0; // No filename anymore
fileinfo[33]=5; // Mark for 5.0 frm file
int4store(fileinfo+34,create_info->avg_row_length);
csid= (create_info->default_table_charset ?
create_info->default_table_charset->number : 0);
fileinfo[38]= (uchar) csid;
fileinfo[39]= (uchar) ((uint) create_info->transactional |
((uint) create_info->page_checksum << 2));
fileinfo[40]= (uchar) create_info->row_type;
/* Next few bytes where for RAID support */
fileinfo[41]= (uchar) (csid >> 8);
fileinfo[42]= 0;
fileinfo[43]= 0;
fileinfo[44]= 0;
fileinfo[45]= 0;
fileinfo[46]= 0;
int4store(fileinfo+47, key_length);
tmp= MYSQL_VERSION_ID; // Store to avoid warning from int4store
int4store(fileinfo+51, tmp);
int4store(fileinfo+55, create_info->extra_size);
/*
59-60 is reserved for extra_rec_buf_length,
61 for default_part_db_type
*/
int2store(fileinfo+62, create_info->key_block_size);
bzero(fill,IO_SIZE);
for (; length > IO_SIZE ; length-= IO_SIZE)
{
if (mysql_file_write(file, fill, IO_SIZE, MYF(MY_WME | MY_NABP)))
{
(void) mysql_file_close(file, MYF(0));
(void) mysql_file_delete(key_file_frm, name, MYF(0));
return(-1);
}
}
}
else
{
if (my_errno == ENOENT)
my_error(ER_BAD_DB_ERROR,MYF(0),db);
else
my_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno);
}
DBUG_RETURN(file);
} /* create_frm */
uint key_length, tmp_key_length, tmp, csid;
bzero((char*) fileinfo, FRM_HEADER_SIZE);
/* header */
fileinfo[0]=(uchar) 254;
fileinfo[1]= 1;
fileinfo[2]= FRM_VER+3+ test(create_info->varchar);
fileinfo[3]= (uchar) ha_legacy_type(
ha_checktype(thd,ha_legacy_type(create_info->db_type),0,0));
int2store(fileinfo+4,3);
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
/*
Keep in sync with pack_keys() in unireg.cc
For each key:
8 bytes for the key header
9 bytes for each key-part (MAX_REF_PARTS)
NAME_LEN bytes for the name
1 byte for the NAMES_SEP_CHAR (before the name)
For all keys:
6 bytes for the header
1 byte for the NAMES_SEP_CHAR (after the last name)
9 extra bytes (padding for safety? alignment?)
*/
for (i= 0; i < keys; i++)
{
DBUG_ASSERT(test(key_info[i].flags & HA_USES_COMMENT) ==
(key_info[i].comment.length > 0));
if (key_info[i].flags & HA_USES_COMMENT)
key_comment_total_bytes += 2 + key_info[i].comment.length;
}
key_length= keys * (8 + MAX_REF_PARTS * 9 + NAME_LEN + 1) + 16
+ key_comment_total_bytes;
length= next_io_size((ulong) (IO_SIZE+key_length+reclength+
create_info->extra_size));
int2store(fileinfo+8,1);
int4store(fileinfo+10,length);
tmp_key_length= (key_length < 0xffff) ? key_length : 0xffff;
int2store(fileinfo+14,tmp_key_length);
int2store(fileinfo+16,reclength);
int4store(fileinfo+18,create_info->max_rows);
int4store(fileinfo+22,create_info->min_rows);
/* fileinfo[26] is set in mysql_create_frm() */
fileinfo[27]=2; // Use long pack-fields
/* fileinfo[28 & 29] is set to key_info_length in mysql_create_frm() */
create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
int2store(fileinfo+30,create_info->table_options);
fileinfo[32]=0; // No filename anymore
fileinfo[33]=5; // Mark for 5.0 frm file
int4store(fileinfo+34,create_info->avg_row_length);
csid= (create_info->default_table_charset ?
create_info->default_table_charset->number : 0);
fileinfo[38]= (uchar) csid;
fileinfo[39]= (uchar) ((uint) create_info->transactional |
((uint) create_info->page_checksum << 2));
fileinfo[40]= (uchar) create_info->row_type;
/* Next few bytes where for RAID support */
fileinfo[41]= (uchar) (csid >> 8);
fileinfo[42]= 0;
fileinfo[43]= 0;
fileinfo[44]= 0;
fileinfo[45]= 0;
fileinfo[46]= 0;
int4store(fileinfo+47, key_length);
tmp= MYSQL_VERSION_ID; // Store to avoid warning from int4store
int4store(fileinfo+51, tmp);
int4store(fileinfo+55, create_info->extra_size);
/*
59-60 is reserved for extra_rec_buf_length,
61 for default_part_db_type
*/
int2store(fileinfo+62, create_info->key_block_size);
DBUG_VOID_RETURN;
} /* prepare_fileinfo */
void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
......
......@@ -2490,17 +2490,28 @@ bool get_field(MEM_ROOT *mem, Field *field, class String *res);
int closefrm(TABLE *table, bool free_share);
void free_blobs(TABLE *table);
void free_field_buffers_larger_than(TABLE *table, uint32 size);
int set_zone(int nr,int min_zone,int max_zone);
ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
const char *newname);
ulong next_io_size(ulong pos);
void append_unescaped(String *res, const char *pos, uint length);
File create_frm(THD *thd, const char *name, const char *db,
const char *table, uint reclength, uchar *fileinfo,
HA_CREATE_INFO *create_info, uint keys, KEY *key_info);
void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo,
HA_CREATE_INFO *create_info, uint keys, KEY *key_info);
char *fn_rext(char *name);
/* Check that the integer is in the internal */
static inline int set_zone(int nr,int min_zone,int max_zone)
{
if (nr <= min_zone)
return min_zone;
if (nr >= max_zone)
return max_zone;
return nr;
}
/* Adjust number to next larger disk buffer */
static inline ulong next_io_size(ulong pos)
{
return MY_ALIGN(pos, IO_SIZE);
}
/* performance schema */
extern LEX_STRING PERFORMANCE_SCHEMA_DB_NAME;
......
......@@ -27,7 +27,6 @@
#include "sql_priv.h"
#include "unireg.h"
#include "sql_partition.h" // struct partition_info
#include "sql_table.h" // check_duplicate_warning
#include "sql_class.h" // THD, Internal_error_handler
#include "create_options.h"
#include <m_ctype.h>
......@@ -38,54 +37,11 @@
/* threshold for safe_alloca */
#define ALLOCA_THRESHOLD 2048
static uchar * pack_screens(List<Create_field> &create_fields,
uint *info_length, uint *screens, bool small_file);
static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
ulong data_offset);
static bool 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);
static uint pack_keys(uchar *,uint, KEY *, ulong);
static bool pack_header(uchar *, List<Create_field> &, uint, ulong, handler *);
static uint get_interval_id(uint *,List<Create_field> &, Create_field *);
static bool pack_fields(File file, List<Create_field> &create_fields,
ulong data_offset);
static bool make_empty_rec(THD *thd, int file, uint table_options,
List<Create_field> &create_fields,
uint reclength, ulong data_offset);
/**
An interceptor to hijack ER_TOO_MANY_FIELDS error from
pack_screens and retry again without UNIREG screens.
XXX: what is a UNIREG screen?
*/
struct Pack_header_error_handler: public Internal_error_handler
{
virtual bool handle_condition(THD *thd,
uint sql_errno,
const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg,
MYSQL_ERROR ** cond_hdl);
bool is_handled;
Pack_header_error_handler() :is_handled(FALSE) {}
};
bool
Pack_header_error_handler::
handle_condition(THD *,
uint sql_errno,
const char*,
MYSQL_ERROR::enum_warning_level,
const char*,
MYSQL_ERROR ** cond_hdl)
{
*cond_hdl= NULL;
is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
return is_handled;
}
static bool pack_fields(File, List<Create_field> &, ulong);
static bool make_empty_rec(THD *, int, uint, List<Create_field> &, uint, ulong);
/*
Create a frm (table definition) file
......@@ -115,25 +71,20 @@ bool mysql_create_frm(THD *thd, const char *file_name,
handler *db_file)
{
LEX_STRING str_db_type;
uint reclength, info_length, screens, key_info_length, maxlength, tmp_len, i;
uint reclength, key_info_length, maxlength, tmp_len, i;
ulong key_buff_length;
File file;
ulong filepos, data_offset;
uint options_len;
uchar fileinfo[64],forminfo[288],*keybuff;
uchar *screen_buff;
uchar fileinfo[FRM_HEADER_SIZE],forminfo[FRM_FORMINFO_SIZE],*keybuff;
char buff[128];
#ifdef WITH_PARTITION_STORAGE_ENGINE
partition_info *part_info= thd->work_part_info;
#endif
Pack_header_error_handler pack_header_error_handler;
int error;
DBUG_ENTER("mysql_create_frm");
DBUG_ASSERT(*fn_rext((char*)file_name)); // Check .frm extension
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
DBUG_RETURN(1);
DBUG_ASSERT(db_file != NULL);
/* If fixed row records, we need one bit to check for deleted rows */
......@@ -141,32 +92,12 @@ bool mysql_create_frm(THD *thd, const char *file_name,
create_info->null_bits++;
data_offset= (create_info->null_bits + 7) / 8;
thd->push_internal_handler(&pack_header_error_handler);
error= pack_header(forminfo, ha_legacy_type(create_info->db_type),
create_fields,info_length,
screens, create_info->table_options,
error= pack_header(forminfo, create_fields, create_info->table_options,
data_offset, db_file);
thd->pop_internal_handler();
if (error)
{
my_free(screen_buff);
if (! pack_header_error_handler.is_handled)
DBUG_RETURN(1);
DBUG_RETURN(1);
// Try again without UNIREG screens (to get more columns)
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
DBUG_RETURN(1);
if (pack_header(forminfo, ha_legacy_type(create_info->db_type),
create_fields,info_length,
screens, create_info->table_options, data_offset, db_file))
{
my_free(screen_buff);
DBUG_RETURN(1);
}
}
reclength=uint2korr(forminfo+266);
/* Calculate extra data segment length */
......@@ -244,16 +175,13 @@ bool mysql_create_frm(THD *thd, const char *file_name,
{
my_error(ER_TOO_LONG_TABLE_COMMENT, MYF(0),
real_table_name, static_cast<ulong>(TABLE_COMMENT_MAXLEN));
my_free(screen_buff);
DBUG_RETURN(1);
}
char warn_buff[MYSQL_ERRMSG_SIZE];
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_TABLE_COMMENT),
real_table_name, static_cast<ulong>(TABLE_COMMENT_MAXLEN));
/* do not push duplicate warnings */
if (!check_duplicate_warning(current_thd, warn_buff, strlen(warn_buff)))
push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TOO_LONG_TABLE_COMMENT, warn_buff);
push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TOO_LONG_TABLE_COMMENT, warn_buff);
create_info->comment.length= tmp_len;
}
/*
......@@ -266,32 +194,43 @@ bool mysql_create_frm(THD *thd, const char *file_name,
forminfo[46]=255;
create_info->extra_size+= 2 + create_info->comment.length;
}
else{
else
{
strmake((char*) forminfo+47, create_info->comment.str ?
create_info->comment.str : "", create_info->comment.length);
forminfo[46]=(uchar) create_info->comment.length;
}
if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
create_info, keys, key_info)) < 0)
{
my_free(screen_buff);
DBUG_RETURN(1);
}
prepare_frm_header(thd, reclength, fileinfo, create_info, keys, key_info);
key_buff_length= uint4korr(fileinfo+47);
keybuff=(uchar*) my_malloc(key_buff_length, MYF(MY_THREAD_SPECIFIC));
key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
/*
Ensure that there are no forms in this newly created form file.
Even if the form file exists, create_frm must truncate it to
ensure one form per form file.
*/
DBUG_ASSERT(uint2korr(fileinfo+8) == 0);
int create_flags= O_RDWR | O_TRUNC;
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags|= O_EXCL | O_NOFOLLOW;
if (!(filepos= make_new_entry(file, fileinfo, NULL, "")))
file= mysql_file_create(key_file_frm, file_name,
CREATE_MODE, create_flags, MYF(0));
if (file < 0)
{
if (my_errno == ENOENT)
my_error(ER_BAD_DB_ERROR,MYF(0),db);
else
my_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno);
my_free(keybuff);
DBUG_RETURN(1);
}
//========================
filepos= uint4korr(fileinfo+10);
mysql_file_seek(file, FRM_HEADER_SIZE, MY_SEEK_SET, MYF(0));
if (mysql_file_write(file, (uchar*)"//", 3, MYF(MY_NABP+MY_WME)) ||
mysql_file_write(file, fileinfo+10, 4, MYF(MY_NABP+MY_WME)))
goto err;
//========================
maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
int2store(forminfo+2,maxlength);
int4store(fileinfo+10,(ulong) (filepos+maxlength));
......@@ -308,7 +247,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
#endif
int2store(fileinfo+59,db_file->extra_rec_buf_length());
if (mysql_file_pwrite(file, fileinfo, 64, 0L, MYF_RW) ||
if (mysql_file_pwrite(file, fileinfo, FRM_HEADER_SIZE, 0L, MYF_RW) ||
mysql_file_pwrite(file, keybuff, key_info_length,
(ulong) uint2korr(fileinfo+6), MYF_RW))
goto err;
......@@ -388,12 +327,10 @@ bool mysql_create_frm(THD *thd, const char *file_name,
}
mysql_file_seek(file, filepos, MY_SEEK_SET, MYF(0));
if (mysql_file_write(file, forminfo, 288, MYF_RW) ||
mysql_file_write(file, screen_buff, info_length, MYF_RW) ||
if (mysql_file_write(file, forminfo, FRM_FORMINFO_SIZE, MYF_RW) ||
pack_fields(file, create_fields, data_offset))
goto err;
my_free(screen_buff);
my_free(keybuff);
if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
......@@ -423,7 +360,6 @@ bool mysql_create_frm(THD *thd, const char *file_name,
DBUG_RETURN(0);
err:
my_free(screen_buff);
my_free(keybuff);
err2:
(void) mysql_file_close(file, MYF(MY_WME));
......@@ -486,82 +422,6 @@ int rea_create_table(THD *thd, const char *path,
} /* 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++))
length+=(uint) strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
if (!(info=(uchar*) my_malloc(length,MYF(MY_WME | MY_THREAD_SPECIFIC))))
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((char *) pos+3,(uint) (cols >> 1),' ');
pos+=(cols >> 1)+4;
}
length=(uint) strlen(cfield->field_name);
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. */
static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
......@@ -647,10 +507,8 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
/* Make formheader */
static bool 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)
static bool pack_header(uchar *forminfo, List<Create_field> &create_fields,
uint table_options, ulong data_offset, handler *file)
{
uint length,int_count,int_length,no_empty, int_parts;
uint time_stamp_pos,null_fields;
......@@ -693,10 +551,8 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_TOO_LONG_FIELD_COMMENT),
field->field_name,
static_cast<ulong>(COLUMN_COMMENT_MAXLEN));
/* do not push duplicate warnings */
if (!check_duplicate_warning(current_thd, warn_buff, strlen(warn_buff)))
push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TOO_LONG_FIELD_COMMENT, warn_buff);
push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TOO_LONG_FIELD_COMMENT, warn_buff);
field->comment.length= tmp_len;
}
if (field->vcol_info)
......@@ -808,7 +664,7 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
}
/* 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+
if ((ulong) create_fields.elements*FCOMP+FRM_FORMINFO_SIZE+
n_length+int_length+com_length+vcol_info_length > 65535L ||
int_count > 255)
{
......@@ -816,13 +672,13 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
DBUG_RETURN(1);
}
bzero((char*)forminfo,288);
length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+
bzero((char*)forminfo,FRM_FORMINFO_SIZE);
length=(create_fields.elements*FCOMP+FRM_FORMINFO_SIZE+n_length+int_length+
com_length+vcol_info_length);
int2store(forminfo,length);
forminfo[256] = (uint8) screens;
forminfo[256] = 0;
int2store(forminfo+258,create_fields.elements);
int2store(forminfo+260,info_length);
int2store(forminfo+260,0);
int2store(forminfo+262,totlength);
int2store(forminfo+264,no_empty);
int2store(forminfo+266,reclength);
......@@ -836,7 +692,6 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
int2store(forminfo+282,null_fields);
int2store(forminfo+284,com_length);
int2store(forminfo+286,vcol_info_length);
/* forminfo+288 is free to use for additional information */
DBUG_RETURN(0);
} /* pack_header */
......@@ -889,9 +744,6 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
{
uint recpos;
uint cur_vcol_expr_len= 0;
buff[0]= (uchar) field->row;
buff[1]= (uchar) field->col;
buff[2]= (uchar) field->sc_length;
int2store(buff+3, field->length);
/* The +1 is here becasue the col offset in .frm file have offset 1 */
recpos= field->offset+1 + (uint) data_offset;
......
......@@ -179,6 +179,9 @@ int rea_create_table(THD *thd, const char *path,
uint key_count,KEY *key_info,
handler *file);
#define FRM_HEADER_SIZE 64
#define FRM_FORMINFO_SIZE 288
static inline bool is_binary_frm_header(uchar *head)
{
return head[0] == 254
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment