summaryrefslogtreecommitdiff
path: root/sql/unireg.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/unireg.cc')
-rw-r--r--sql/unireg.cc836
1 files changed, 304 insertions, 532 deletions
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 528c3025c57..12d3c265a86 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2013, Monty Program Ab.
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
@@ -24,151 +25,107 @@
str is a (long) to record position where 0 is the first position.
*/
+#include <my_global.h>
#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 "discover.h"
#include <m_ctype.h>
-#include <assert.h>
#define FCOMP 17 /* Bytes for a packed field */
/* 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(THD *, 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, enum legacy_db_type table_type,
- uint table_options,
- List<Create_field> &create_fields,
- uint reclength, ulong data_offset,
- handler *handler);
-
-/**
- An interceptor to hijack ER_TOO_MANY_FIELDS error from
- pack_screens and retry again without UNIREG screens.
+static bool pack_fields(uchar *, List<Create_field> &, ulong);
+static size_t packed_fields_length(List<Create_field> &);
+static bool make_empty_rec(THD *, uchar *, uint, List<Create_field> &, uint, ulong);
- XXX: what is a UNIREG screen?
+/*
+ write the length as
+ if ( 0 < length <= 255) one byte
+ if (256 < length <= 65535) zero byte, then two bytes, low-endian
*/
+static uchar *extra2_write_len(uchar *pos, size_t len)
+{
+ if (len <= 255)
+ *pos++= len;
+ else
+ {
+ /*
+ At the moment we support options_len up to 64K.
+ We can easily extend it in the future, if the need arises.
+ */
+ DBUG_ASSERT(len <= 65535);
+ int2store(pos + 1, len);
+ pos+= 3;
+ }
+ return pos;
+}
-struct Pack_header_error_handler: public Internal_error_handler
+static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type,
+ LEX_STRING *str)
{
- 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)
+ *pos++ = type;
+ pos= extra2_write_len(pos, str->length);
+ memcpy(pos, str->str, str->length);
+ return pos + str->length;
+}
+
+static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type,
+ LEX_CUSTRING *str)
{
- *cond_hdl= NULL;
- is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
- return is_handled;
+ return extra2_write(pos, type, reinterpret_cast<LEX_STRING *>(str));
}
-/*
+/**
Create a frm (table definition) file
- SYNOPSIS
- mysql_create_frm()
- thd Thread handler
- file_name Path for file (including database and .frm)
- db Name of database
- table Name of table
- 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
- create_info->db_type
- RETURN
- false ok
- true error
+ @param thd Thread handler
+ @param table Name of table
+ @param create_info create info parameters
+ @param create_fields Fields to create
+ @param keys number of keys to create
+ @param key_info Keys to create
+ @param db_file Handler to use.
+
+ @return the generated frm image as a LEX_CUSTRING,
+ or null LEX_CUSTRING (str==0) in case of an error.
*/
-bool 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)
+LEX_CUSTRING build_frm_image(THD *thd, const char *table,
+ HA_CREATE_INFO *create_info,
+ List<Create_field> &create_fields,
+ uint keys, KEY *key_info, 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, i;
ulong key_buff_length;
- File file;
ulong filepos, data_offset;
uint options_len;
- uchar fileinfo[64],forminfo[288],*keybuff;
- uchar *screen_buff;
- 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;
+ uchar fileinfo[FRM_HEADER_SIZE],forminfo[FRM_FORMINFO_SIZE];
+ const partition_info *part_info= IF_PARTITIONING(thd->work_part_info, 0);
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);
+ uchar *frm_ptr, *pos;
+ LEX_CUSTRING frm= {0,0};
+ DBUG_ENTER("build_frm_image");
/* 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;
- 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(thd, 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);
-
- // 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);
- }
- }
+ DBUG_RETURN(frm);
+
reclength=uint2korr(forminfo+266);
/* Calculate extra data segment length */
@@ -184,12 +141,8 @@ bool mysql_create_frm(THD *thd, const char *file_name,
=> Total 6 byte
*/
create_info->extra_size+= 6;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
if (part_info)
- {
create_info->extra_size+= part_info->part_info_len;
- }
-#endif
for (i= 0; i < keys; i++)
{
@@ -201,234 +154,164 @@ bool mysql_create_frm(THD *thd, const char *file_name,
create_fields,
keys, key_info);
DBUG_PRINT("info", ("Options length: %u", options_len));
- if (options_len)
- {
- create_info->table_options|= HA_OPTION_TEXT_CREATE_OPTIONS;
- create_info->extra_size+= (options_len + 4);
- }
- else
- create_info->table_options&= ~HA_OPTION_TEXT_CREATE_OPTIONS;
-
- /*
- This gives us the byte-position of the character at
- (character-position, not byte-position) TABLE_COMMENT_MAXLEN.
- The trick here is that character-positions start at 0, so the last
- character in a maximum-allowed length string would be at char-pos
- MAXLEN-1; charpos MAXLEN will be the position of the terminator.
- Consequently, bytepos(charpos(MAXLEN)) should be equal to
- comment[length] (which should also be the terminator, or at least
- the first byte after the payload in the strict sense). If this is
- not so (bytepos(charpos(MAXLEN)) comes /before/ the end of the
- string), the string is too long.
-
- For additional credit, realise that UTF-8 has 1-3 bytes before 6.0,
- and 1-4 bytes in 6.0 (6.0 also has UTF-32).
- */
- tmp_len= system_charset_info->cset->charpos(system_charset_info,
- create_info->comment.str,
- create_info->comment.str +
- create_info->comment.length,
- TABLE_COMMENT_MAXLEN);
- if (tmp_len < create_info->comment.length)
- {
- char *real_table_name= (char*) table;
- List_iterator<Create_field> it(create_fields);
- Create_field *field;
- while ((field=it++))
- {
- if (field->field && field->field->table &&
- (real_table_name= field->field->table->s->table_name.str))
- break;
- }
- if ((thd->variables.sql_mode &
- (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
- {
- 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);
- create_info->comment.length= tmp_len;
- }
+ if (validate_comment_length(thd, &create_info->comment, TABLE_COMMENT_MAXLEN,
+ ER_TOO_LONG_TABLE_COMMENT, table))
+ DBUG_RETURN(frm);
/*
If table comment is longer than TABLE_COMMENT_INLINE_MAXLEN bytes,
store the comment in an extra segment (up to TABLE_COMMENT_MAXLEN bytes).
- Pre 6.0, the limit was 60 characters, with no extra segment-handling.
+ Pre 5.5, the limit was 60 characters, with no extra segment-handling.
*/
if (create_info->comment.length > TABLE_COMMENT_INLINE_MAXLEN)
{
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)
+ if (!create_info->tabledef_version.str)
{
- my_free(screen_buff);
- DBUG_RETURN(1);
+ uchar *to= (uchar*) thd->alloc(MY_UUID_SIZE);
+ if (unlikely(!to))
+ DBUG_RETURN(frm);
+ my_uuid(to);
+ create_info->tabledef_version.str= to;
+ create_info->tabledef_version.length= MY_UUID_SIZE;
}
+ DBUG_ASSERT(create_info->tabledef_version.length > 0);
+ DBUG_ASSERT(create_info->tabledef_version.length <= 255);
+
+ prepare_frm_header(thd, reclength, fileinfo, create_info, keys, key_info);
+
+ /* one byte for a type, one or three for a length */
+ uint extra2_size= 1 + 1 + create_info->tabledef_version.length;
+ if (options_len)
+ extra2_size+= 1 + (options_len > 255 ? 3 : 1) + options_len;
+
+ if (part_info)
+ extra2_size+= 1 + 1 + hton_name(part_info->default_engine_type)->length;
key_buff_length= uint4korr(fileinfo+47);
- keybuff=(uchar*) my_malloc(key_buff_length, MYF(0));
- 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);
+ frm.length= FRM_HEADER_SIZE; // fileinfo;
+ frm.length+= extra2_size + 4; // mariadb extra2 frm segment
- if (!(filepos= make_new_entry(file, fileinfo, NULL, "")))
- goto err;
- maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000));
- int2store(forminfo+2,maxlength);
- int4store(fileinfo+10,(ulong) (filepos+maxlength));
- fileinfo[26]= (uchar) test((create_info->max_rows == 1) &&
- (create_info->min_rows == 1) && (keys == 0));
+ int2store(fileinfo+4, extra2_size);
+ int2store(fileinfo+6, frm.length); // Position to key information
+ frm.length+= key_buff_length;
+ frm.length+= reclength; // row with default values
+ frm.length+= create_info->extra_size;
+
+ filepos= frm.length;
+ frm.length+= FRM_FORMINFO_SIZE; // forminfo
+ frm.length+= packed_fields_length(create_fields);
+
+ if (frm.length > FRM_MAX_SIZE)
+ {
+ my_error(ER_TABLE_DEFINITION_TOO_BIG, MYF(0), table);
+ DBUG_RETURN(frm);
+ }
+
+ frm_ptr= (uchar*) my_malloc(frm.length, MYF(MY_WME | MY_ZEROFILL |
+ MY_THREAD_SPECIFIC));
+ if (!frm_ptr)
+ DBUG_RETURN(frm);
+
+ /* write the extra2 segment */
+ pos = frm_ptr + 64;
+ compile_time_assert(EXTRA2_TABLEDEF_VERSION != '/');
+ pos= extra2_write(pos, EXTRA2_TABLEDEF_VERSION,
+ &create_info->tabledef_version);
+
+ if (part_info)
+ pos= extra2_write(pos, EXTRA2_DEFAULT_PART_ENGINE,
+ hton_name(part_info->default_engine_type));
+
+ if (options_len)
+ {
+ *pos++= EXTRA2_ENGINE_TABLEOPTS;
+ pos= extra2_write_len(pos, options_len);
+ pos= engine_table_options_frm_image(pos, create_info->option_list,
+ create_fields, keys, key_info);
+ }
+
+ int4store(pos, filepos); // end of the extra2 segment
+ pos+= 4;
+
+ DBUG_ASSERT(pos == frm_ptr + uint2korr(fileinfo+6));
+ key_info_length= pack_keys(pos, keys, key_info, data_offset);
+
+ int2store(forminfo+2, frm.length - filepos);
+ int4store(fileinfo+10, frm.length);
+ fileinfo[26]= (uchar) MY_TEST((create_info->max_rows == 1) &&
+ (create_info->min_rows == 1) && (keys == 0));
int2store(fileinfo+28,key_info_length);
-#ifdef WITH_PARTITION_STORAGE_ENGINE
if (part_info)
{
fileinfo[61]= (uchar) ha_legacy_type(part_info->default_engine_type);
DBUG_PRINT("info", ("part_db_type = %d", fileinfo[61]));
}
-#endif
- int2store(fileinfo+59,db_file->extra_rec_buf_length());
- if (mysql_file_pwrite(file, fileinfo, 64, 0L, MYF_RW) ||
- mysql_file_pwrite(file, keybuff, key_info_length,
- (ulong) uint2korr(fileinfo+6), MYF_RW))
- goto err;
- mysql_file_seek(file,
- (ulong) uint2korr(fileinfo+6) + (ulong) key_buff_length,
- MY_SEEK_SET, MYF(0));
- if (make_empty_rec(thd,file,ha_legacy_type(create_info->db_type),
- create_info->table_options,
- create_fields,reclength, data_offset, db_file))
- goto err;
+ int2store(fileinfo+59,db_file->extra_rec_buf_length());
- int2store(buff, create_info->connect_string.length);
- if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
- mysql_file_write(file, (const uchar*)create_info->connect_string.str,
- create_info->connect_string.length, MYF(MY_NABP)))
- goto err;
+ memcpy(frm_ptr, fileinfo, FRM_HEADER_SIZE);
- int2store(buff, str_db_type.length);
- if (mysql_file_write(file, (const uchar*)buff, 2, MYF(MY_NABP)) ||
- mysql_file_write(file, (const uchar*)str_db_type.str,
- str_db_type.length, MYF(MY_NABP)))
+ pos+= key_buff_length;
+ if (make_empty_rec(thd, pos, create_info->table_options, create_fields,
+ reclength, data_offset))
goto err;
-#ifdef WITH_PARTITION_STORAGE_ENGINE
+ pos+= reclength;
+ int2store(pos, create_info->connect_string.length);
+ pos+= 2;
+ memcpy(pos, create_info->connect_string.str, create_info->connect_string.length);
+ pos+= create_info->connect_string.length;
+ int2store(pos, str_db_type.length);
+ pos+= 2;
+ memcpy(pos, str_db_type.str, str_db_type.length);
+ pos+= str_db_type.length;
+
if (part_info)
{
char auto_partitioned= part_info->is_auto_partitioned ? 1 : 0;
- int4store(buff, part_info->part_info_len);
- if (mysql_file_write(file, (const uchar*)buff, 4, MYF_RW) ||
- mysql_file_write(file, (const uchar*)part_info->part_info_string,
- part_info->part_info_len + 1, MYF_RW) ||
- mysql_file_write(file, (const uchar*)&auto_partitioned, 1, MYF_RW))
- goto err;
+ int4store(pos, part_info->part_info_len);
+ pos+= 4;
+ memcpy(pos, part_info->part_info_string, part_info->part_info_len + 1);
+ pos+= part_info->part_info_len + 1;
+ *pos++= auto_partitioned;
}
else
-#endif
{
- bzero((uchar*) buff, 6);
- if (mysql_file_write(file, (uchar*) buff, 6, MYF_RW))
- goto err;
+ pos+= 6;
}
for (i= 0; i < keys; i++)
{
if (key_info[i].parser_name)
{
- if (mysql_file_write(file, (const uchar*)key_info[i].parser_name->str,
- key_info[i].parser_name->length + 1, MYF(MY_NABP)))
- goto err;
+ memcpy(pos, key_info[i].parser_name->str, key_info[i].parser_name->length + 1);
+ pos+= key_info[i].parser_name->length + 1;
}
}
- if (forminfo[46] == (uchar)255)
+ if (forminfo[46] == (uchar)255) // New style MySQL 5.5 table comment
{
- uchar comment_length_buff[2];
- int2store(comment_length_buff,create_info->comment.length);
- if (mysql_file_write(file, comment_length_buff, 2, MYF(MY_NABP)) ||
- mysql_file_write(file, (uchar*) create_info->comment.str,
- create_info->comment.length, MYF(MY_NABP)))
- goto err;
+ int2store(pos, create_info->comment.length);
+ pos+=2;
+ memcpy(pos, create_info->comment.str, create_info->comment.length);
+ pos+= create_info->comment.length;
}
- if (options_len)
- {
- uchar *optbuff= (uchar *)my_safe_alloca(options_len + 4, ALLOCA_THRESHOLD);
- my_bool error;
- DBUG_PRINT("info", ("Create options length: %u", options_len));
- if (!optbuff)
- goto err;
- int4store(optbuff, options_len);
- engine_table_options_frm_image(optbuff + 4,
- create_info->option_list,
- create_fields,
- keys, key_info);
- error= my_write(file, optbuff, options_len + 4, MYF_RW);
- my_safe_afree(optbuff, options_len + 4, ALLOCA_THRESHOLD);
- if (error)
- goto err;
- }
-
- 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) ||
- pack_fields(file, create_fields, data_offset))
+ memcpy(frm_ptr + filepos, forminfo, 288);
+ if (pack_fields(frm_ptr + filepos + 288, create_fields, data_offset))
goto err;
-#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 || mysql_file_pwrite(file, &tmp, 1, 26, MYF_RW))// Mark crypted
- goto err;
- uint read_length=uint2korr(forminfo)-256;
- mysql_file_seek(file, filepos+256, MY_SEEK_SET, MYF(0));
- if (read_string(file,(uchar**) &disk_buff,read_length))
- goto err;
- crypted->encode(disk_buff,read_length);
- delete crypted;
- if (mysql_file_pwrite(file, disk_buff, read_length, filepos+256, MYF_RW))
- {
- my_free(disk_buff);
- goto err;
- }
- my_free(disk_buff);
- }
-#endif
-
- my_free(screen_buff);
- my_free(keybuff);
-
- if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
- (mysql_file_sync(file, MYF(MY_WME)) ||
- my_sync_dir_by_file(file_name, MYF(MY_WME))))
- goto err2;
-
- if (mysql_file_close(file, MYF(MY_WME)))
- goto err3;
-
{
/*
Restore all UCS2 intervals.
@@ -445,149 +328,68 @@ bool mysql_create_frm(THD *thd, const char *file_name,
}
}
}
- DBUG_RETURN(0);
+
+ frm.str= frm_ptr;
+ DBUG_RETURN(frm);
err:
- my_free(screen_buff);
- my_free(keybuff);
-err2:
- (void) mysql_file_close(file, MYF(MY_WME));
-err3:
- mysql_file_delete(key_file_frm, file_name, MYF(0));
- DBUG_RETURN(1);
-} /* mysql_create_frm */
+ my_free(frm_ptr);
+ DBUG_RETURN(frm);
+}
-/*
+/**
Create a frm (table definition) file and the tables
- SYNOPSIS
- rea_create_table()
- thd Thread handler
- path Name of file (including database, without .frm)
- db Data base name
- table_name Table name
- create_info create info parameters
- create_fields Fields to create
- keys number of keys to create
- key_info Keys to create
- file Handler to use
-
- RETURN
- 0 ok
- 1 error
+ @param thd Thread handler
+ @param frm Binary frm image of the table to create
+ @param path Name of file (including database, without .frm)
+ @param db Data base name
+ @param table_name Table name
+ @param create_info create info parameters
+ @param file Handler to use or NULL if only frm needs to be created
+
+ @retval 0 ok
+ @retval 1 error
*/
-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)
+int rea_create_table(THD *thd, LEX_CUSTRING *frm,
+ const char *path, const char *db, const char *table_name,
+ HA_CREATE_INFO *create_info, handler *file,
+ bool no_ha_create_table)
{
DBUG_ENTER("rea_create_table");
- char frm_name[FN_REFLEN];
- strxmov(frm_name, path, reg_ext, NullS);
- if (mysql_create_frm(thd, frm_name, db, table_name, create_info,
- create_fields, keys, key_info, file))
-
- DBUG_RETURN(1);
+ // TODO don't write frm for temp tables
+ if (no_ha_create_table || create_info->tmp_table())
+ {
+ if (writefrm(path, db, table_name, true, frm->str, frm->length))
+ goto err_frm;
+ }
- // Make sure mysql_create_frm din't remove extension
- DBUG_ASSERT(*fn_rext(frm_name));
if (thd->variables.keep_files_on_create)
create_info->options|= HA_CREATE_KEEP_FILES;
- if (!create_info->frm_only &&
- (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG,
- create_info) ||
- ha_create_table(thd, path, db, table_name, create_info, 0)))
- goto err_handler;
- DBUG_RETURN(0);
-
-err_handler:
- (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info);
- mysql_file_delete(key_file_frm, frm_name, MYF(0));
- DBUG_RETURN(1);
-} /* 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);
+ if (file->ha_create_partitioning_metadata(path, NULL, CHF_CREATE_FLAG))
+ goto err_part;
- 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))))
- DBUG_RETURN(0);
-
- start_screen=0;
- row=end_row;
- pos=info;
- it.rewind();
- for (i=0 ; i < fields ; i++)
+ if (!no_ha_create_table)
{
- 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));
+ if (ha_create_table(thd, path, db, table_name, create_info, frm))
+ goto err_part;
}
- 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 */
+ DBUG_RETURN(0);
+
+err_part:
+ file->ha_create_partitioning_metadata(path, NULL, CHF_DELETE_FLAG);
+err_frm:
+ deletefrm(path);
+ DBUG_RETURN(1);
+} /* rea_create_table */
- /* Pack keyinfo and keynames to keybuff for save in form-file. */
+/* Pack keyinfo and keynames to keybuff for save in form-file. */
static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
ulong data_offset)
@@ -604,15 +406,15 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
{
int2store(pos, (key->flags ^ HA_NOSAME));
int2store(pos+2,key->key_length);
- pos[4]= (uchar) key->key_parts;
+ pos[4]= (uchar) key->user_defined_key_parts;
pos[5]= (uchar) key->algorithm;
int2store(pos+6, key->block_size);
pos+=8;
- key_parts+=key->key_parts;
+ key_parts+=key->user_defined_key_parts;
DBUG_PRINT("loop", ("flags: %lu key_parts: %d key_part: 0x%lx",
- key->flags, key->key_parts,
+ key->flags, key->user_defined_key_parts,
(long) key->key_part));
- for (key_part=key->key_part,key_part_end=key_part+key->key_parts ;
+ for (key_part=key->key_part,key_part_end=key_part+key->user_defined_key_parts ;
key_part != key_part_end ;
key_part++)
@@ -670,12 +472,11 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
} /* pack_keys */
- /* Make formheader */
+/* 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(THD *thd, 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;
@@ -694,45 +495,23 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
com_length=vcol_info_length=0;
n_length=2L;
- /* Check fields */
-
+ /* Check fields */
List_iterator<Create_field> it(create_fields);
Create_field *field;
while ((field=it++))
{
- uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
- field->comment.str,
- field->comment.str +
- field->comment.length,
- COLUMN_COMMENT_MAXLEN);
- if (tmp_len < field->comment.length)
- {
- if ((current_thd->variables.sql_mode &
- (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)))
- {
- my_error(ER_TOO_LONG_FIELD_COMMENT, MYF(0), field->field_name,
- static_cast<ulong>(COLUMN_COMMENT_MAXLEN));
- DBUG_RETURN(1);
- }
- char warn_buff[MYSQL_ERRMSG_SIZE];
- 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);
- field->comment.length= tmp_len;
- }
+ if (validate_comment_length(thd, &field->comment, COLUMN_COMMENT_MAXLEN,
+ ER_TOO_LONG_FIELD_COMMENT, field->field_name))
+ DBUG_RETURN(1);
+
if (field->vcol_info)
{
uint col_expr_maxlen= field->virtual_col_expr_maxlen();
- tmp_len=
- system_charset_info->cset->charpos(system_charset_info,
- field->vcol_info->expr_str.str,
- field->vcol_info->expr_str.str +
- field->vcol_info->expr_str.length,
- col_expr_maxlen);
+ uint tmp_len= my_charpos(system_charset_info,
+ field->vcol_info->expr_str.str,
+ field->vcol_info->expr_str.str +
+ field->vcol_info->expr_str.length,
+ col_expr_maxlen);
if (tmp_len < field->vcol_info->expr_str.length)
{
@@ -747,7 +526,7 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
expressions saved in the frm file for virtual columns.
*/
vcol_info_length+= field->vcol_info->expr_str.length+
- FRM_VCOL_HEADER_SIZE(field->interval!=NULL);
+ FRM_VCOL_HEADER_SIZE(field->interval);
}
totlength+= field->length;
@@ -824,16 +603,15 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
}
int_length+=int_count*2; // 255 prefix + 0 suffix
- /* Save values in forminfo */
-
+ /* Save values in forminfo */
if (reclength > (ulong) file->max_record_length())
{
my_error(ER_TOO_BIG_ROWSIZE, MYF(0), static_cast<long>(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+
+ reclength=MY_MAX(file->min_record_length(table_options),reclength);
+ if ((ulong) create_fields.elements*FCOMP+FRM_FORMINFO_SIZE+
n_length+int_length+com_length+vcol_info_length > 65535L ||
int_count > 255)
{
@@ -841,13 +619,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);
@@ -861,13 +639,11 @@ 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 */
- /* get each unique interval each own id */
-
+/* get each unique interval each own id */
static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
Create_field *last_field)
{
@@ -894,29 +670,57 @@ static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
}
- /* Save fields, fieldnames and intervals */
+static size_t packed_fields_length(List<Create_field> &create_fields)
+{
+ Create_field *field;
+ size_t length= 0;
+ DBUG_ENTER("packed_fields_length");
+
+ List_iterator<Create_field> it(create_fields);
+ uint int_count=0;
+ while ((field=it++))
+ {
+ if (field->interval_id > int_count)
+ {
+ int_count= field->interval_id;
+ length++;
+ for (int i=0; field->interval->type_names[i]; i++)
+ {
+ length+= field->interval->type_lengths[i];
+ length++;
+ }
+ length++;
+ }
+ if (field->vcol_info)
+ {
+ length+= field->vcol_info->expr_str.length +
+ FRM_VCOL_HEADER_SIZE(field->interval);
+ }
+ length+= FCOMP;
+ length+= strlen(field->field_name)+1;
+ length+= field->comment.length;
+ }
+ length++;
+ length++;
+ DBUG_RETURN(length);
+}
+
+/* Save fields, fieldnames and intervals */
-static bool pack_fields(File file, List<Create_field> &create_fields,
+static bool pack_fields(uchar *buff, List<Create_field> &create_fields,
ulong data_offset)
{
- reg2 uint i;
uint int_count, comment_length= 0, vcol_info_length=0;
- uchar buff[MAX_FIELD_WIDTH];
Create_field *field;
DBUG_ENTER("pack_fields");
- /* Write field info */
-
+ /* Write field info */
List_iterator<Create_field> it(create_fields);
-
int_count=0;
while ((field=it++))
{
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;
@@ -950,40 +754,29 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
the additional data saved for the virtual field
*/
buff[12]= cur_vcol_expr_len= field->vcol_info->expr_str.length +
- FRM_VCOL_HEADER_SIZE(field->interval!=NULL);
- vcol_info_length+= cur_vcol_expr_len +
- FRM_VCOL_HEADER_SIZE(field->interval!=NULL);
+ FRM_VCOL_HEADER_SIZE(field->interval);
+ vcol_info_length+= cur_vcol_expr_len;
buff[13]= (uchar) MYSQL_TYPE_VIRTUAL;
}
int2store(buff+15, field->comment.length);
comment_length+= field->comment.length;
set_if_bigger(int_count,field->interval_id);
- if (mysql_file_write(file, buff, FCOMP, MYF_RW))
- DBUG_RETURN(1);
+ buff+= FCOMP;
}
- /* Write fieldnames */
- buff[0]=(uchar) NAMES_SEP_CHAR;
- if (mysql_file_write(file, buff, 1, MYF_RW))
- DBUG_RETURN(1);
- i=0;
+ /* Write fieldnames */
+ *buff++= NAMES_SEP_CHAR;
it.rewind();
while ((field=it++))
{
- char *pos= strmov((char*) buff,field->field_name);
- * (uchar*) pos++= (uchar) NAMES_SEP_CHAR;
- if (i == create_fields.elements-1)
- *pos++=0;
- if (mysql_file_write(file, buff, (size_t) (pos-(char*) buff), MYF_RW))
- DBUG_RETURN(1);
- i++;
+ buff= (uchar*)strmov((char*) buff, field->field_name);
+ *buff++=NAMES_SEP_CHAR;
}
+ *buff++= 0;
- /* Write intervals */
+ /* Write intervals */
if (int_count)
{
- String tmp((char*) buff,sizeof(buff), &my_charset_bin);
- tmp.length(0);
it.rewind();
int_count=0;
while ((field=it++))
@@ -1025,34 +818,30 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
}
int_count= field->interval_id;
- tmp.append(sep);
- for (const char **pos=field->interval->type_names ; *pos ; pos++)
+ *buff++= sep;
+ for (int i=0; field->interval->type_names[i]; i++)
{
- tmp.append(*pos);
- tmp.append(sep);
+ memcpy(buff, field->interval->type_names[i], field->interval->type_lengths[i]);
+ buff+= field->interval->type_lengths[i];
+ *buff++= sep;
}
- tmp.append('\0'); // End of intervall
+ *buff++= 0;
+
}
}
- if (mysql_file_write(file, (uchar*) tmp.ptr(), tmp.length(), MYF_RW))
- DBUG_RETURN(1);
}
if (comment_length)
{
it.rewind();
- int_count=0;
while ((field=it++))
{
- if (field->comment.length)
- if (mysql_file_write(file, (uchar*) field->comment.str,
- field->comment.length, MYF_RW))
- DBUG_RETURN(1);
+ memcpy(buff, field->comment.str, field->comment.length);
+ buff+= field->comment.length;
}
}
if (vcol_info_length)
{
it.rewind();
- int_count=0;
while ((field=it++))
{
/*
@@ -1065,18 +854,13 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
*/
if (field->vcol_info && field->vcol_info->expr_str.length)
{
- buff[0]= (uchar)(1 + test(field->interval_id));
- buff[1]= (uchar) field->sql_type;
- buff[2]= (uchar) field->stored_in_db;
- if (field->interval_id)
- buff[3]= (uchar) field->interval_id;
- if (my_write(file, buff, 3 + test(field->interval_id), MYF_RW))
- DBUG_RETURN(1);
- if (my_write(file,
- (uchar*) field->vcol_info->expr_str.str,
- field->vcol_info->expr_str.length,
- MYF_RW))
- DBUG_RETURN(1);
+ *buff++= (uchar) (1 + MY_TEST(field->interval));
+ *buff++= (uchar) field->sql_type;
+ *buff++= (uchar) field->stored_in_db;
+ if (field->interval)
+ *buff++= (uchar) field->interval_id;
+ memcpy(buff, field->vcol_info->expr_str.str, field->vcol_info->expr_str.length);
+ buff+= field->vcol_info->expr_str.length;
}
}
}
@@ -1084,19 +868,16 @@ static bool pack_fields(File file, List<Create_field> &create_fields,
}
- /* save an empty record on start of formfile */
+/* save an empty record on start of formfile */
-static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
- uint table_options,
+static bool make_empty_rec(THD *thd, uchar *buff, uint table_options,
List<Create_field> &create_fields,
- uint reclength,
- ulong data_offset,
- handler *handler)
+ uint reclength, ulong data_offset)
{
int error= 0;
Field::utype type;
uint null_count;
- uchar *buff,*null_pos;
+ uchar *null_pos;
TABLE table;
TABLE_SHARE share;
Create_field *field;
@@ -1108,13 +889,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
bzero((char*) &share, sizeof(share));
table.s= &share;
- if (!(buff=(uchar*) my_malloc((size_t) reclength,MYF(MY_WME | MY_ZEROFILL))))
- {
- DBUG_RETURN(1);
- }
-
table.in_use= thd;
- table.s->blob_ptr_size= portable_sizeof_char_ptr;
null_count=0;
if (!(table_options & HA_OPTION_PACK_RECORD))
@@ -1198,10 +973,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
if (null_count & 7)
*(null_pos + null_count / 8)|= ~(((uchar) 1 << (null_count & 7)) - 1);
- error= mysql_file_write(file, buff, (size_t) reclength, MYF_RW) != 0;
-
err:
- my_free(buff);
thd->count_cuted_fields= old_count_cuted_fields;
DBUG_RETURN(error);
} /* make_empty_rec */