table.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:44k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* Some general useful functions */
  14. #include "mysql_priv.h"
  15. #include <errno.h>
  16. #include <m_ctype.h>
  17. /* Functions defined in this file */
  18. static void frm_error(int error,TABLE *form,const char *name,
  19.                       int errortype, int errarg);
  20. static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
  21.       uint types, char **names);
  22. static uint find_field(TABLE *form,uint start,uint length);
  23. static byte* get_field_name(Field **buff,uint *length,
  24.     my_bool not_used __attribute__((unused)))
  25. {
  26.   *length= (uint) strlen((*buff)->field_name);
  27.   return (byte*) (*buff)->field_name;
  28. }
  29. /*
  30.   Open a .frm file 
  31.   SYNOPSIS
  32.     openfrm()
  33.     name           path to table-file "db/name"
  34.     alias          alias for table
  35.     db_stat        open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..)
  36.                    can be 0 (example in ha_example_table)
  37.     prgflag        READ_ALL etc..
  38.     ha_open_flags  HA_OPEN_ABORT_IF_LOCKED etc..
  39.     outparam       result table
  40.   RETURN VALUES
  41.    0 ok
  42.    1 Error (see frm_error)
  43.    2    Error (see frm_error)
  44.    3    Wrong data in .frm file
  45.    4    Error (see frm_error)
  46.    5    Error (see frm_error: charset unavailable)
  47.    6    Unknown .frm version
  48. */
  49. int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
  50.     uint ha_open_flags, TABLE *outparam)
  51. {
  52.   reg1 uint i;
  53.   reg2 uchar *strpos;
  54.   int  j,error, errarg= 0;
  55.   uint  rec_buff_length,n_length,int_length,records,key_parts,keys,
  56.          interval_count,interval_parts,read_length,db_create_options;
  57.   uint  key_info_length, com_length;
  58.   ulong  pos;
  59.   char  index_file[FN_REFLEN], *names, *keynames, *comment_pos;
  60.   uchar  head[288],*disk_buff,new_field_pack_flag;
  61.   my_string record;
  62.   const char **int_array;
  63.   bool  use_hash, null_field_first;
  64.   File  file;
  65.   Field  **field_ptr,*reg_field;
  66.   KEY  *keyinfo;
  67.   KEY_PART_INFO *key_part;
  68.   uchar *null_pos;
  69.   uint null_bit, new_frm_ver, field_pack_length;
  70.   SQL_CRYPT *crypted=0;
  71.   MEM_ROOT **root_ptr, *old_root;
  72.   DBUG_ENTER("openfrm");
  73.   DBUG_PRINT("enter",("name: '%s'  form: %lx",name,outparam));
  74.   bzero((char*) outparam,sizeof(*outparam));
  75.   outparam->blob_ptr_size=sizeof(char*);
  76.   disk_buff=NULL; record= NULL; keynames=NullS;
  77.   outparam->db_stat = db_stat;
  78.   error=1;
  79.   init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
  80.   root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
  81.   old_root= *root_ptr;
  82.   *root_ptr= &outparam->mem_root;
  83.   outparam->real_name=strdup_root(&outparam->mem_root,
  84.                                   name+dirname_length(name));
  85.   outparam->table_name=my_strdup(alias,MYF(MY_WME));
  86.   if (!outparam->real_name || !outparam->table_name)
  87.     goto err_end;
  88.   *fn_ext(outparam->real_name)=''; // Remove extension
  89.   if ((file=my_open(fn_format(index_file,name,"",reg_ext,MY_UNPACK_FILENAME),
  90.     O_RDONLY | O_SHARE,
  91.     MYF(0)))
  92.       < 0)
  93.   {
  94.     goto err_end; /* purecov: inspected */
  95.   }
  96.   error=4;
  97.   if (!(outparam->path= strdup_root(&outparam->mem_root,name)))
  98.     goto err_not_open;
  99.   *fn_ext(outparam->path)=''; // Remove extension
  100.   if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err_not_open;
  101.   if (head[0] != (uchar) 254 || head[1] != 1)
  102.     goto err_not_open; /* purecov: inspected */
  103.   if (head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3)
  104.   {
  105.     error= 6;
  106.     goto err_not_open; /* purecov: inspected */
  107.   }
  108.   new_field_pack_flag=head[27];
  109.   new_frm_ver= (head[2] - FRM_VER);
  110.   field_pack_length= new_frm_ver < 2 ? 11 : 17;
  111.   error=3;
  112.   if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
  113.     goto err_not_open; /* purecov: inspected */
  114.   *fn_ext(index_file)=''; // Remove .frm extension
  115.   outparam->frm_version= head[2];
  116.   outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
  117.   outparam->db_create_options=db_create_options=uint2korr(head+30);
  118.   outparam->db_options_in_use=outparam->db_create_options;
  119.   null_field_first=0;
  120.   if (!head[32]) // New frm file in 3.23
  121.   {
  122.     outparam->avg_row_length=uint4korr(head+34);
  123.     outparam->row_type=(row_type) head[40];
  124.     outparam->raid_type=   head[41];
  125.     outparam->raid_chunks= head[42];
  126.     outparam->raid_chunksize= uint4korr(head+43);
  127.     outparam->table_charset=get_charset((uint) head[38],MYF(0));
  128.     null_field_first=1;
  129.   }
  130.   if (!outparam->table_charset)
  131.   {
  132.     /* unknown charset in head[38] or pre-3.23 frm */
  133.     if (use_mb(default_charset_info))
  134.     {
  135.       /* Warn that we may be changing the size of character columns */
  136.       sql_print_warning("'%s' had no or invalid character set, "
  137.                         "and default character set is multi-byte, "
  138.                         "so character column sizes may have changed",
  139.                         name);
  140.     }
  141.     outparam->table_charset=default_charset_info;
  142.   }
  143.   outparam->db_record_offset=1;
  144.   if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
  145.     outparam->blob_ptr_size=portable_sizeof_char_ptr;
  146.   /* Set temporaryly a good value for db_low_byte_first */
  147.   outparam->db_low_byte_first=test(outparam->db_type != DB_TYPE_ISAM);
  148.   error=4;
  149.   outparam->max_rows=uint4korr(head+18);
  150.   outparam->min_rows=uint4korr(head+22);
  151.   /* Read keyinformation */
  152.   key_info_length= (uint) uint2korr(head+28);
  153.   VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
  154.   if (read_string(file,(gptr*) &disk_buff,key_info_length))
  155.     goto err_not_open; /* purecov: inspected */
  156.   if (disk_buff[0] & 0x80)
  157.   {
  158.     outparam->keys=      keys=      (disk_buff[1] << 7) | (disk_buff[0] & 0x7f);
  159.     outparam->key_parts= key_parts= uint2korr(disk_buff+2);
  160.   }
  161.   else
  162.   {
  163.     outparam->keys=      keys=      disk_buff[0];
  164.     outparam->key_parts= key_parts= disk_buff[1];
  165.   }
  166.   outparam->keys_for_keyread.init(0);
  167.   outparam->keys_in_use.init(keys);
  168.   outparam->read_only_keys.init(keys);
  169.   outparam->quick_keys.init();
  170.   outparam->used_keys.init();
  171.   outparam->keys_in_use_for_query.init();
  172.   n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
  173.   if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
  174.     n_length+uint2korr(disk_buff+4))))
  175.     goto err_not_open; /* purecov: inspected */
  176.   bzero((char*) keyinfo,n_length);
  177.   outparam->key_info=keyinfo;
  178.   key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys);
  179.   strpos=disk_buff+6;
  180.   ulong *rec_per_key;
  181.   if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root,
  182.  sizeof(ulong*)*key_parts)))
  183.     goto err_not_open;
  184.   for (i=0 ; i < keys ; i++, keyinfo++)
  185.   {
  186.     if (new_frm_ver == 3)
  187.     {
  188.       keyinfo->flags=    (uint) uint2korr(strpos) ^ HA_NOSAME;
  189.       keyinfo->key_length= (uint) uint2korr(strpos+2);
  190.       keyinfo->key_parts=  (uint) strpos[4];
  191.       keyinfo->algorithm=  (enum ha_key_alg) strpos[5];
  192.       strpos+=8;
  193.     }
  194.     else
  195.     {
  196.       keyinfo->flags=  ((uint) strpos[0]) ^ HA_NOSAME;
  197.       keyinfo->key_length= (uint) uint2korr(strpos+1);
  198.       keyinfo->key_parts=  (uint) strpos[3];
  199.       keyinfo->algorithm= HA_KEY_ALG_UNDEF;
  200.       strpos+=4;
  201.     }
  202.     keyinfo->key_part=  key_part;
  203.     keyinfo->rec_per_key= rec_per_key;
  204.     for (j=keyinfo->key_parts ; j-- ; key_part++)
  205.     {
  206.       *rec_per_key++=0;
  207.       key_part->fieldnr= (uint16) (uint2korr(strpos) & FIELD_NR_MASK);
  208.       key_part->offset= (uint) uint2korr(strpos+2)-1;
  209.       key_part->key_type= (uint) uint2korr(strpos+5);
  210.       // key_part->field= (Field*) 0; // Will be fixed later
  211.       if (new_frm_ver >= 1)
  212.       {
  213. key_part->key_part_flag= *(strpos+4);
  214. key_part->length= (uint) uint2korr(strpos+7);
  215. strpos+=9;
  216.       }
  217.       else
  218.       {
  219. key_part->length= *(strpos+4);
  220. key_part->key_part_flag=0;
  221. if (key_part->length > 128)
  222. {
  223.   key_part->length&=127; /* purecov: inspected */
  224.   key_part->key_part_flag=HA_REVERSE_SORT; /* purecov: inspected */
  225. }
  226. strpos+=7;
  227.       }
  228.       key_part->store_length=key_part->length;
  229.     }
  230.   }
  231.   keynames=(char*) key_part;
  232.   strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
  233.   outparam->reclength = uint2korr((head+16));
  234.   if (*(head+26) == 1)
  235.     outparam->system=1; /* one-record-database */
  236. #ifdef HAVE_CRYPTED_FRM
  237.   else if (*(head+26) == 2)
  238.   {
  239.     *root_ptr= old_root
  240.     crypted=get_crypt_for_frm();
  241.     *root_ptr= &outparam->mem_root;
  242.     outparam->crypted=1;
  243.   }
  244. #endif
  245.   /* Allocate handler */
  246.   if (!(outparam->file= get_new_handler(outparam,outparam->db_type)))
  247.     goto err_not_open;
  248.   error=4;
  249.   outparam->reginfo.lock_type= TL_UNLOCK;
  250.   outparam->current_lock=F_UNLCK;
  251.   if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=2;
  252.   else records=1;
  253.   if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
  254.   /* QQ: TODO, remove the +1 from below */
  255.   rec_buff_length=ALIGN_SIZE(outparam->reclength+1+
  256.      outparam->file->extra_rec_buf_length());
  257.   if (!(outparam->record[0]= (byte*)
  258. (record = (char *) alloc_root(&outparam->mem_root,
  259.       rec_buff_length * records))))
  260.     goto err_not_open; /* purecov: inspected */
  261.   record[outparam->reclength]=0; // For purify and ->c_ptr()
  262.   outparam->rec_buff_length=rec_buff_length;
  263.   if (my_pread(file,(byte*) record,(uint) outparam->reclength,
  264.        (ulong) (uint2korr(head+6)+
  265.                         ((uint2korr(head+14) == 0xffff ?
  266.                             uint4korr(head+47) : uint2korr(head+14)))),
  267.        MYF(MY_NABP)))
  268.     goto err_not_open; /* purecov: inspected */
  269.   /* HACK: table->record[2] is used instead of table->default_values here */
  270.   for (i=0 ; i < records ; i++, record+=rec_buff_length)
  271.   {
  272.     outparam->record[i]=(byte*) record;
  273.     if (i)
  274.       memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
  275.   }
  276.   if (records == 2)
  277.   { /* fix for select */
  278.     outparam->default_values=outparam->record[1];
  279.     if (db_stat & HA_READ_ONLY)
  280.       outparam->record[1]=outparam->record[0]; /* purecov: inspected */
  281.   }
  282.   outparam->insert_values=0;                   /* for INSERT ... UPDATE */
  283.   VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
  284.   if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
  285. #ifdef HAVE_CRYPTED_FRM
  286.   if (crypted)
  287.   {
  288.     crypted->decode((char*) head+256,288-256);
  289.     if (sint2korr(head+284) != 0) // Should be 0
  290.       goto err_not_open; // Wrong password
  291.   }
  292. #endif
  293.   outparam->fields= uint2korr(head+258);
  294.   pos=uint2korr(head+260); /* Length of all screens */
  295.   n_length=uint2korr(head+268);
  296.   interval_count=uint2korr(head+270);
  297.   interval_parts=uint2korr(head+272);
  298.   int_length=uint2korr(head+274);
  299.   outparam->null_fields=uint2korr(head+282);
  300.   com_length=uint2korr(head+284);
  301.   outparam->comment=strdup_root(&outparam->mem_root,
  302. (char*) head+47);
  303.   DBUG_PRINT("info",("i_count: %d  i_parts: %d  index: %d  n_length: %d  int_length: %d  com_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length, com_length));
  304.   if (!(field_ptr = (Field **)
  305. alloc_root(&outparam->mem_root,
  306.    (uint) ((outparam->fields+1)*sizeof(Field*)+
  307.    interval_count*sizeof(TYPELIB)+
  308.    (outparam->fields+interval_parts+
  309.     keys+3)*sizeof(my_string)+
  310.    (n_length+int_length+com_length)))))
  311.     goto err_not_open; /* purecov: inspected */
  312.   outparam->field=field_ptr;
  313.   read_length=(uint) (outparam->fields * field_pack_length +
  314.       pos+ (uint) (n_length+int_length+com_length));
  315.   if (read_string(file,(gptr*) &disk_buff,read_length))
  316.     goto err_not_open; /* purecov: inspected */
  317. #ifdef HAVE_CRYPTED_FRM
  318.   if (crypted)
  319.   {
  320.     crypted->decode((char*) disk_buff,read_length);
  321.     delete crypted;
  322.     crypted=0;
  323.   }
  324. #endif
  325.   strpos= disk_buff+pos;
  326.   outparam->intervals= (TYPELIB*) (field_ptr+outparam->fields+1);
  327.   int_array= (const char **) (outparam->intervals+interval_count);
  328.   names= (char*) (int_array+outparam->fields+interval_parts+keys+3);
  329.   if (!interval_count)
  330.     outparam->intervals=0; // For better debugging
  331.   memcpy((char*) names, strpos+(outparam->fields*field_pack_length),
  332.  (uint) (n_length+int_length));
  333.   comment_pos=names+(n_length+int_length);
  334.   memcpy(comment_pos, disk_buff+read_length-com_length, com_length);
  335.   fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
  336.   fix_type_pointers(&int_array,outparam->intervals,interval_count,
  337.     &names);
  338.   {
  339.     /* Set ENUM and SET lengths */
  340.     TYPELIB *interval;
  341.     for (interval= outparam->intervals;
  342.          interval < outparam->intervals + interval_count;
  343.          interval++)
  344.     {
  345.       uint count= (uint) (interval->count + 1) * sizeof(uint);
  346.       if (!(interval->type_lengths= (uint *) alloc_root(&outparam->mem_root,
  347.                                                         count)))
  348.         goto err_not_open;
  349.       for (count= 0; count < interval->count; count++)
  350.         interval->type_lengths[count]= strlen(interval->type_names[count]);
  351.       interval->type_lengths[count]= 0;
  352.     }
  353.   }
  354.   if (keynames)
  355.     fix_type_pointers(&int_array,&outparam->keynames,1,&keynames);
  356.   VOID(my_close(file,MYF(MY_WME)));
  357.   file= -1;
  358.   record=(char*) outparam->record[0]-1; /* Fieldstart = 1 */
  359.   if (null_field_first)
  360.   {
  361.     outparam->null_flags=null_pos=(uchar*) record+1;
  362.     null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
  363.     outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
  364.   }
  365.   else
  366.   {
  367.     outparam->null_bytes=(outparam->null_fields+7)/8;
  368.     outparam->null_flags=null_pos=
  369.       (uchar*) (record+1+outparam->reclength-outparam->null_bytes);
  370.     null_bit=1;
  371.   }
  372.   use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
  373.   if (use_hash)
  374.     use_hash= !hash_init(&outparam->name_hash,
  375.  system_charset_info,
  376.  outparam->fields,0,0,
  377.  (hash_get_key) get_field_name,0,0);
  378.   for (i=0 ; i < outparam->fields; i++, strpos+=field_pack_length, field_ptr++)
  379.   {
  380.     uint pack_flag, interval_nr, unireg_type, recpos, field_length;
  381.     enum_field_types field_type;
  382.     CHARSET_INFO *charset=NULL;
  383.     Field::geometry_type geom_type= Field::GEOM_GEOMETRY;
  384.     LEX_STRING comment;
  385.     if (new_frm_ver == 3)
  386.     {
  387.       /* new frm file in 4.1 */
  388.       field_length= uint2korr(strpos+3);
  389.       recpos=     uint3korr(strpos+5);
  390.       pack_flag=    uint2korr(strpos+8);
  391.       unireg_type=  (uint) strpos[10];
  392.       interval_nr=  (uint) strpos[12];
  393.       uint comment_length=uint2korr(strpos+15);
  394.       field_type=(enum_field_types) (uint) strpos[13];
  395.       // charset and geometry_type share the same byte in frm
  396.       if (field_type == FIELD_TYPE_GEOMETRY)
  397.       {
  398. #ifdef HAVE_SPATIAL
  399. geom_type= (Field::geometry_type) strpos[14];
  400. charset= &my_charset_bin;
  401. #else
  402. error= 4;  // unsupported field type
  403. goto err_not_open;
  404. #endif
  405.       }
  406.       else
  407.       {
  408.         if (!strpos[14])
  409.           charset= &my_charset_bin;
  410.         else if (!(charset=get_charset((uint) strpos[14], MYF(0))))
  411.         {
  412.           error= 5; // Unknown or unavailable charset
  413.           errarg= (int) strpos[14];
  414.           goto err_not_open;
  415.         }
  416.       }
  417.       if (!comment_length)
  418.       {
  419. comment.str= (char*) "";
  420. comment.length=0;
  421.       }
  422.       else
  423.       {
  424. comment.str=    (char*) comment_pos;
  425. comment.length= comment_length;
  426. comment_pos+=   comment_length;
  427.       }
  428.     }
  429.     else
  430.     {
  431.       field_length= (uint) strpos[3];
  432.       recpos=     uint2korr(strpos+4),
  433.       pack_flag=    uint2korr(strpos+6);
  434.       unireg_type=  (uint) strpos[8];
  435.       interval_nr=  (uint) strpos[10];
  436.       /* old frm file */
  437.       field_type= (enum_field_types) f_packtype(pack_flag);
  438.       if (f_is_binary(pack_flag))
  439.       {
  440.         /*
  441.           Try to choose the best 4.1 type:
  442.           - for 4.0 "CHAR(N) BINARY" or "VARCHAR(N) BINARY" 
  443.             try to find a binary collation for character set.
  444.           - for other types (e.g. BLOB) just use my_charset_bin. 
  445.         */
  446.         if (!f_is_blob(pack_flag))
  447.         {
  448.           // 3.23 or 4.0 string
  449.           if (!(charset= get_charset_by_csname(outparam->table_charset->csname,
  450.                                                MY_CS_BINSORT, MYF(0))))
  451.             charset= &my_charset_bin;
  452.         }
  453.         else
  454.           charset= &my_charset_bin;
  455.       }
  456.       else
  457.         charset= outparam->table_charset;
  458.       bzero((char*) &comment, sizeof(comment));
  459.     }
  460.     if (interval_nr && charset->mbminlen > 1)
  461.     {
  462.       /* Unescape UCS2 intervals from HEX notation */
  463.       TYPELIB *interval= outparam->intervals + interval_nr - 1;
  464.       unhex_type2(interval);
  465.     }
  466.     
  467.     *field_ptr=reg_field=
  468.       make_field(record+recpos,
  469.  (uint32) field_length,
  470.  null_pos,null_bit,
  471.  pack_flag,
  472.  field_type,
  473.  charset,
  474.  geom_type,
  475.  (Field::utype) MTYP_TYPENR(unireg_type),
  476.  (interval_nr ?
  477.   outparam->intervals+interval_nr-1 :
  478.   (TYPELIB*) 0),
  479.  outparam->fieldnames.type_names[i],
  480.  outparam);
  481.     if (!reg_field) // Not supported field type
  482.     {
  483.       error= 4;
  484.       goto err_not_open; /* purecov: inspected */
  485.     }
  486.     reg_field->comment=comment;
  487.     if (!(reg_field->flags & NOT_NULL_FLAG))
  488.     {
  489.       if ((null_bit<<=1) == 256)
  490.       {
  491. null_pos++;
  492. null_bit=1;
  493.       }
  494.     }
  495.     if (reg_field->unireg_check == Field::NEXT_NUMBER)
  496.       outparam->found_next_number_field= reg_field;
  497.     if (outparam->timestamp_field == reg_field)
  498.       outparam->timestamp_field_offset=i;
  499.     if (use_hash)
  500.       (void) my_hash_insert(&outparam->name_hash,(byte*) field_ptr); // Will never fail
  501.   }
  502.   *field_ptr=0; // End marker
  503.   /* Fix key->name and key_part->field */
  504.   if (key_parts)
  505.   {
  506.     uint primary_key=(uint) (find_type((char*) primary_key_name,
  507.        &outparam->keynames, 3) - 1);
  508.     uint ha_option=outparam->file->table_flags();
  509.     keyinfo=outparam->key_info;
  510.     key_part=keyinfo->key_part;
  511.     for (uint key=0 ; key < outparam->keys ; key++,keyinfo++)
  512.     {
  513.       uint usable_parts=0;
  514.       keyinfo->name=(char*) outparam->keynames.type_names[key];
  515.       /* Fix fulltext keys for old .frm files */
  516.       if (outparam->key_info[key].flags & HA_FULLTEXT)
  517. outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT;
  518.       if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
  519.       {
  520. /*
  521.   If the UNIQUE key doesn't have NULL columns and is not a part key
  522.   declare this as a primary key.
  523. */
  524. primary_key=key;
  525. for (i=0 ; i < keyinfo->key_parts ;i++)
  526. {
  527.   uint fieldnr= key_part[i].fieldnr;
  528.   if (!fieldnr ||
  529.       outparam->field[fieldnr-1]->null_ptr ||
  530.       outparam->field[fieldnr-1]->key_length() !=
  531.       key_part[i].length)
  532.   {
  533.     primary_key=MAX_KEY; // Can't be used
  534.     break;
  535.   }
  536. }
  537.       }
  538.       for (i=0 ; i < keyinfo->key_parts ; key_part++,i++)
  539.       {
  540. if (new_field_pack_flag <= 1)
  541.   key_part->fieldnr=(uint16) find_field(outparam,
  542. (uint) key_part->offset,
  543. (uint) key_part->length);
  544. #ifdef EXTRA_DEBUG
  545. if (key_part->fieldnr > outparam->fields)
  546.   goto err_not_open; // sanity check
  547. #endif
  548. if (key_part->fieldnr)
  549. { // Should always be true !
  550.   Field *field=key_part->field=outparam->field[key_part->fieldnr-1];
  551.   if (field->null_ptr)
  552.   {
  553.     key_part->null_offset=(uint) ((byte*) field->null_ptr -
  554.   outparam->record[0]);
  555.     key_part->null_bit= field->null_bit;
  556.     key_part->store_length+=HA_KEY_NULL_LENGTH;
  557.     keyinfo->flags|=HA_NULL_PART_KEY;
  558.     keyinfo->extra_length+= HA_KEY_NULL_LENGTH;
  559.     keyinfo->key_length+= HA_KEY_NULL_LENGTH;
  560.   }
  561.   if (field->type() == FIELD_TYPE_BLOB ||
  562.       field->real_type() == FIELD_TYPE_VAR_STRING)
  563.   {
  564.     if (field->type() == FIELD_TYPE_BLOB)
  565.       key_part->key_part_flag|= HA_BLOB_PART;
  566.     keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
  567.     key_part->store_length+=HA_KEY_BLOB_LENGTH;
  568.     keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
  569.     /*
  570.       Mark that there may be many matching values for one key
  571.       combination ('a', 'a ', 'a  '...)
  572.     */
  573.     if (!(field->flags & BINARY_FLAG))
  574.       keyinfo->flags|= HA_END_SPACE_KEY;
  575.   }
  576.   if (i == 0 && key != primary_key)
  577.     field->flags |=
  578.       ((keyinfo->flags & HA_NOSAME) &&
  579.        field->key_length() ==
  580.        keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
  581.   if (i == 0)
  582.     field->key_start.set_bit(key);
  583.   if (field->key_length() == key_part->length &&
  584.       !(field->flags & BLOB_FLAG))
  585.   {
  586.             if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY)
  587.             {
  588.               outparam->read_only_keys.clear_bit(key);
  589.               outparam->keys_for_keyread.set_bit(key);
  590.       field->part_of_key.set_bit(key);
  591.             }
  592.     if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER)
  593.       field->part_of_sortkey.set_bit(key);
  594.   }
  595.   if (!(key_part->key_part_flag & HA_REVERSE_SORT) &&
  596.       usable_parts == i)
  597.     usable_parts++; // For FILESORT
  598.   field->flags|= PART_KEY_FLAG;
  599.   if (key == primary_key)
  600.   {
  601.     field->flags|= PRI_KEY_FLAG;
  602.     /*
  603.       If this field is part of the primary key and all keys contains
  604.       the primary key, then we can use any key to find this column
  605.     */
  606.     if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)
  607.       field->part_of_key= outparam->keys_in_use;
  608.   }
  609.   if (field->key_length() != key_part->length)
  610.   {
  611.     key_part->key_part_flag|= HA_PART_KEY_SEG;
  612.     if (!(field->flags & BLOB_FLAG))
  613.     { // Create a new field
  614.       field=key_part->field=field->new_field(&outparam->mem_root,
  615.      outparam);
  616.       field->field_length=key_part->length;
  617.     }
  618.   }
  619.   /*
  620.     If the field can be NULL, don't optimize away the test
  621.     key_part_column = expression from the WHERE clause
  622.     as we need to test for NULL = NULL.
  623.   */
  624.   if (field->real_maybe_null())
  625.     key_part->key_part_flag|= HA_PART_KEY_SEG;
  626. }
  627. else
  628. { // Error: shorten key
  629.   keyinfo->key_parts=usable_parts;
  630.   keyinfo->flags=0;
  631. }
  632.       }
  633.       keyinfo->usable_key_parts=usable_parts; // Filesort
  634.       set_if_bigger(outparam->max_key_length,keyinfo->key_length+
  635.     keyinfo->key_parts);
  636.       outparam->total_key_length+= keyinfo->key_length;
  637.       /*
  638.         MERGE tables do not have unique indexes. But every key could be
  639.         an unique index on the underlying MyISAM table. (Bug #10400)
  640.       */
  641.       if ((keyinfo->flags & HA_NOSAME) ||
  642.           (ha_option & HA_ANY_INDEX_MAY_BE_UNIQUE))
  643.         set_if_bigger(outparam->max_unique_length,keyinfo->key_length);
  644.     }
  645.     if (primary_key < MAX_KEY &&
  646. (outparam->keys_in_use.is_set(primary_key)))
  647.     {
  648.       outparam->primary_key=primary_key;
  649.       /*
  650. If we are using an integer as the primary key then allow the user to
  651. refer to it as '_rowid'
  652.       */
  653.       if (outparam->key_info[primary_key].key_parts == 1)
  654.       {
  655. Field *field= outparam->key_info[primary_key].key_part[0].field;
  656. if (field && field->result_type() == INT_RESULT)
  657.   outparam->rowid_field=field;
  658.       }
  659.     }
  660.     else
  661.       outparam->primary_key = MAX_KEY; // we do not have a primary key
  662.   }
  663.   else
  664.     outparam->primary_key= MAX_KEY;
  665.   x_free((gptr) disk_buff);
  666.   disk_buff=0;
  667.   if (new_field_pack_flag <= 1)
  668.   { /* Old file format with default null */
  669.     uint null_length=(outparam->null_fields+7)/8;
  670.     bfill(outparam->null_flags,null_length,255);
  671.     bfill(outparam->null_flags+outparam->rec_buff_length,null_length,255);
  672.     if (records > 2)
  673.       bfill(outparam->null_flags+outparam->rec_buff_length*2,null_length,255);
  674.   }
  675.   if ((reg_field=outparam->found_next_number_field))
  676.   {
  677.     if ((int) (outparam->next_number_index= (uint)
  678.        find_ref_key(outparam,reg_field,
  679.     &outparam->next_number_key_offset)) < 0)
  680.     {
  681.       reg_field->unireg_check=Field::NONE; /* purecov: inspected */
  682.       outparam->found_next_number_field=0;
  683.     }
  684.     else
  685.       reg_field->flags|=AUTO_INCREMENT_FLAG;
  686.   }
  687.   if (outparam->blob_fields)
  688.   {
  689.     Field **ptr;
  690.     Field_blob **save;
  691.     if (!(outparam->blob_field=save=
  692.   (Field_blob**) alloc_root(&outparam->mem_root,
  693.     (uint) (outparam->blob_fields+1)*
  694.     sizeof(Field_blob*))))
  695.       goto err_not_open;
  696.     for (ptr=outparam->field ; *ptr ; ptr++)
  697.     {
  698.       if ((*ptr)->flags & BLOB_FLAG)
  699. (*save++)= (Field_blob*) *ptr;
  700.     }
  701.     *save=0; // End marker
  702.   }
  703.   else
  704.     outparam->blob_field=
  705.       (Field_blob**) (outparam->field+outparam->fields); // Point at null ptr
  706.   /* The table struct is now initialzed;  Open the table */
  707.   error=2;
  708.   if (db_stat)
  709.   {
  710.     int err;
  711.     unpack_filename(index_file,index_file);
  712.     if ((err=(outparam->file->
  713.       ha_open(index_file,
  714.       (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
  715.       (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
  716.        ((db_stat & HA_WAIT_IF_LOCKED) ||
  717. (specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
  718.        HA_OPEN_WAIT_IF_LOCKED :
  719.        (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
  720.        HA_OPEN_ABORT_IF_LOCKED :
  721.        HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
  722.     {
  723.       /* Set a flag if the table is crashed and it can be auto. repaired */
  724.       outparam->crashed=((err == HA_ERR_CRASHED_ON_USAGE) &&
  725.  outparam->file->auto_repair() &&
  726.  !(ha_open_flags & HA_OPEN_FOR_REPAIR));
  727.       if (err==HA_ERR_NO_SUCH_TABLE)
  728.       {
  729. /* The table did not exists in storage engine, use same error message
  730.    as if the .frm file didn't exist */
  731. error= 1;
  732. my_errno= ENOENT;
  733.       }
  734.       goto err_not_open; /* purecov: inspected */
  735.     }
  736.   }
  737.   outparam->db_low_byte_first=outparam->file->low_byte_first();
  738.   *root_ptr= old_root;
  739.   opened_tables++;
  740. #ifndef DBUG_OFF
  741.   if (use_hash)
  742.     (void) hash_check(&outparam->name_hash);
  743. #endif
  744.   DBUG_RETURN (0);
  745.  err_not_open:
  746.   x_free((gptr) disk_buff);
  747.   if (file > 0)
  748.     VOID(my_close(file,MYF(MY_WME)));
  749.  err_end: /* Here when no file */
  750.   delete crypted;
  751.   *root_ptr= old_root;
  752.   frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg);
  753.   delete outparam->file;
  754.   outparam->file=0; // For easyer errorchecking
  755.   outparam->db_stat=0;
  756.   hash_free(&outparam->name_hash);
  757.   free_root(&outparam->mem_root,MYF(0));
  758.   my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
  759.   DBUG_RETURN (error);
  760. } /* openfrm */
  761. /* close a .frm file and it's tables */
  762. int closefrm(register TABLE *table)
  763. {
  764.   int error=0;
  765.   DBUG_ENTER("closefrm");
  766.   if (table->db_stat)
  767.     error=table->file->close();
  768.   if (table->table_name)
  769.   {
  770.     my_free(table->table_name,MYF(0));
  771.     table->table_name=0;
  772.   }
  773.   if (table->fields)
  774.   {
  775.     for (Field **ptr=table->field ; *ptr ; ptr++)
  776.       delete *ptr;
  777.     table->fields=0;
  778.   }
  779.   delete table->file;
  780.   table->file=0; /* For easyer errorchecking */
  781.   hash_free(&table->name_hash);
  782.   free_root(&table->mem_root,MYF(0));
  783.   DBUG_RETURN(error);
  784. }
  785. /* Deallocate temporary blob storage */
  786. void free_blobs(register TABLE *table)
  787. {
  788.   for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
  789.     (*ptr)->free();
  790. }
  791. /* Find where a form starts */
  792. /* if formname is NullS then only formnames is read */
  793. ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
  794. {
  795.   uint a_length,names,length;
  796.   uchar *pos,*buf;
  797.   ulong ret_value=0;
  798.   DBUG_ENTER("get_form_pos");
  799.   names=uint2korr(head+8);
  800.   a_length=(names+2)*sizeof(my_string); /* Room for two extra */
  801.   if (!save_names)
  802.     a_length=0;
  803.   else
  804.     save_names->type_names=0; /* Clear if error */
  805.   if (names)
  806.   {
  807.     length=uint2korr(head+4);
  808.     VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0)));
  809.     if (!(buf= (uchar*) my_malloc((uint) length+a_length+names*4,
  810.   MYF(MY_WME))) ||
  811. my_read(file,(byte*) buf+a_length,(uint) (length+names*4),
  812. MYF(MY_NABP)))
  813.     { /* purecov: inspected */
  814.       x_free((gptr) buf); /* purecov: inspected */
  815.       DBUG_RETURN(0L); /* purecov: inspected */
  816.     }
  817.     pos= buf+a_length+length;
  818.     ret_value=uint4korr(pos);
  819.   }
  820.   if (! save_names)
  821.     my_free((gptr) buf,MYF(0));
  822.   else if (!names)
  823.     bzero((char*) save_names,sizeof(save_names));
  824.   else
  825.   {
  826.     char *str;
  827.     str=(char *) (buf+a_length);
  828.     fix_type_pointers((const char ***) &buf,save_names,1,&str);
  829.   }
  830.   DBUG_RETURN(ret_value);
  831. }
  832. /* Read string from a file with malloc */
  833. int read_string(File file, gptr *to, uint length)
  834. {
  835.   DBUG_ENTER("read_string");
  836.   x_free((gptr) *to);
  837.   if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
  838.       my_read(file,(byte*) *to,length,MYF(MY_NABP)))
  839.   {
  840.     x_free((gptr) *to); /* purecov: inspected */
  841.     *to= 0; /* purecov: inspected */
  842.     DBUG_RETURN(1); /* purecov: inspected */
  843.   }
  844.   *((char*) *to+length)= '';
  845.   DBUG_RETURN (0);
  846. } /* read_string */
  847. /* Add a new form to a form file */
  848. ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
  849.      const char *newname)
  850. {
  851.   uint i,bufflength,maxlength,n_length,length,names;
  852.   ulong endpos,newpos;
  853.   char buff[IO_SIZE];
  854.   uchar *pos;
  855.   DBUG_ENTER("make_new_entry");
  856.   length=(uint) strlen(newname)+1;
  857.   n_length=uint2korr(fileinfo+4);
  858.   maxlength=uint2korr(fileinfo+6);
  859.   names=uint2korr(fileinfo+8);
  860.   newpos=uint4korr(fileinfo+10);
  861.   if (64+length+n_length+(names+1)*4 > maxlength)
  862.   { /* Expand file */
  863.     newpos+=IO_SIZE;
  864.     int4store(fileinfo+10,newpos);
  865.     endpos=(ulong) my_seek(file,0L,MY_SEEK_END,MYF(0));/* Copy from file-end */
  866.     bufflength= (uint) (endpos & (IO_SIZE-1)); /* IO_SIZE is a power of 2 */
  867.     while (endpos > maxlength)
  868.     {
  869.       VOID(my_seek(file,(ulong) (endpos-bufflength),MY_SEEK_SET,MYF(0)));
  870.       if (my_read(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
  871. DBUG_RETURN(0L);
  872.       VOID(my_seek(file,(ulong) (endpos-bufflength+IO_SIZE),MY_SEEK_SET,
  873.    MYF(0)));
  874.       if ((my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME))))
  875. DBUG_RETURN(0);
  876.       endpos-=bufflength; bufflength=IO_SIZE;
  877.     }
  878.     bzero(buff,IO_SIZE); /* Null new block */
  879.     VOID(my_seek(file,(ulong) maxlength,MY_SEEK_SET,MYF(0)));
  880.     if (my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
  881. DBUG_RETURN(0L);
  882.     maxlength+=IO_SIZE; /* Fix old ref */
  883.     int2store(fileinfo+6,maxlength);
  884.     for (i=names, pos= (uchar*) *formnames->type_names+n_length-1; i-- ;
  885.  pos+=4)
  886.     {
  887.       endpos=uint4korr(pos)+IO_SIZE;
  888.       int4store(pos,endpos);
  889.     }
  890.   }
  891.   if (n_length == 1 )
  892.   { /* First name */
  893.     length++;
  894.     VOID(strxmov(buff,"/",newname,"/",NullS));
  895.   }
  896.   else
  897.     VOID(strxmov(buff,newname,"/",NullS)); /* purecov: inspected */
  898.   VOID(my_seek(file,63L+(ulong) n_length,MY_SEEK_SET,MYF(0)));
  899.   if (my_write(file,(byte*) buff,(uint) length+1,MYF(MY_NABP+MY_WME)) ||
  900.       (names && my_write(file,(byte*) (*formnames->type_names+n_length-1),
  901.  names*4, MYF(MY_NABP+MY_WME))) ||
  902.       my_write(file,(byte*) fileinfo+10,(uint) 4,MYF(MY_NABP+MY_WME)))
  903.     DBUG_RETURN(0L); /* purecov: inspected */
  904.   int2store(fileinfo+8,names+1);
  905.   int2store(fileinfo+4,n_length+length);
  906.   VOID(my_chsize(file, newpos, 0, MYF(MY_WME)));/* Append file with '' */
  907.   DBUG_RETURN(newpos);
  908. } /* make_new_entry */
  909. /* error message when opening a form file */
  910. static void frm_error(int error, TABLE *form, const char *name,
  911.                       myf errortype, int errarg)
  912. {
  913.   int err_no;
  914.   char buff[FN_REFLEN];
  915.   const char *form_dev="",*datext;
  916.   DBUG_ENTER("frm_error");
  917.   switch (error) {
  918.   case 1:
  919.     if (my_errno == ENOENT)
  920.     {
  921.       char *db;
  922.       uint length=dirname_part(buff,name);
  923.       buff[length-1]=0;
  924.       db=buff+dirname_length(buff);
  925.       my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->real_name);
  926.     }
  927.     else
  928.       my_error(ER_FILE_NOT_FOUND,errortype,
  929.        fn_format(buff,name,form_dev,reg_ext,0),my_errno);
  930.     break;
  931.   case 2:
  932.   {
  933.     datext= form->file ? *form->file->bas_ext() : "";
  934.     datext= datext==NullS ? "" : datext;
  935.     err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
  936.       ER_FILE_USED : ER_CANT_OPEN_FILE;
  937.     my_error(err_no,errortype,
  938.      fn_format(buff,form->real_name,form_dev,datext,2),my_errno);
  939.     break;
  940.   }
  941.   case 5:
  942.   {
  943.     const char *csname= get_charset_name((uint) errarg);
  944.     char tmp[10];
  945.     if (!csname || csname[0] =='?')
  946.     {
  947.       my_snprintf(tmp, sizeof(tmp), "#%d", errarg);
  948.       csname= tmp;
  949.     }
  950.     my_printf_error(ER_UNKNOWN_COLLATION,
  951.                     "Unknown collation '%s' in table '%-.64s' definition", 
  952.                     MYF(0), csname, form->real_name);
  953.     break;
  954.   }
  955.   case 6:
  956.     my_printf_error(ER_NOT_FORM_FILE,
  957.                     "Table '%-.64s' was created with a different version "
  958.                     "of MySQL and cannot be read",
  959.                     MYF(0), name);
  960.     break;
  961.   default: /* Better wrong error than none */
  962.   case 4:
  963.     my_error(ER_NOT_FORM_FILE,errortype,
  964.      fn_format(buff,name,form_dev,reg_ext,0));
  965.     break;
  966.   }
  967.   DBUG_VOID_RETURN;
  968. } /* frm_error */
  969. /*
  970. ** fix a str_type to a array type
  971. ** typeparts sepearated with some char. differents types are separated
  972. ** with a ''
  973. */
  974. static void
  975. fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types,
  976.   char **names)
  977. {
  978.   char *type_name, *ptr;
  979.   char chr;
  980.   ptr= *names;
  981.   while (types--)
  982.   {
  983.     point_to_type->name=0;
  984.     point_to_type->type_names= *array;
  985.     if ((chr= *ptr)) /* Test if empty type */
  986.     {
  987.       while ((type_name=strchr(ptr+1,chr)) != NullS)
  988.       {
  989. *((*array)++) = ptr+1;
  990. *type_name= ''; /* End string */
  991. ptr=type_name;
  992.       }
  993.       ptr+=2; /* Skip end mark and last 0 */
  994.     }
  995.     else
  996.       ptr++;
  997.     point_to_type->count= (uint) (*array - point_to_type->type_names);
  998.     point_to_type++;
  999.     *((*array)++)= NullS; /* End of type */
  1000.   }
  1001.   *names=ptr; /* Update end */
  1002.   return;
  1003. } /* fix_type_pointers */
  1004. TYPELIB *typelib(MEM_ROOT *mem_root, List<String> &strings)
  1005. {
  1006.   TYPELIB *result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
  1007.   if (!result)
  1008.     return 0;
  1009.   result->count=strings.elements;
  1010.   result->name="";
  1011.   uint nbytes= (sizeof(char*) + sizeof(uint)) * (result->count + 1);
  1012.   if (!(result->type_names= (const char**) alloc_root(mem_root, nbytes)))
  1013.     return 0;
  1014.   result->type_lengths= (uint*) (result->type_names + result->count + 1);
  1015.   List_iterator<String> it(strings);
  1016.   String *tmp;
  1017.   for (uint i=0; (tmp=it++) ; i++)
  1018.   {
  1019.     result->type_names[i]= tmp->ptr();
  1020.     result->type_lengths[i]= tmp->length();
  1021.   }
  1022.   result->type_names[result->count]= 0; // End marker
  1023.   result->type_lengths[result->count]= 0;
  1024.   return result;
  1025. }
  1026. /*
  1027. ** Search after a field with given start & length
  1028. ** If an exact field isn't found, return longest field with starts
  1029. ** at right position.
  1030. ** Return 0 on error, else field number+1
  1031. ** This is needed because in some .frm fields 'fieldnr' was saved wrong
  1032. */
  1033. static uint find_field(TABLE *form,uint start,uint length)
  1034. {
  1035.   Field **field;
  1036.   uint i,pos;
  1037.   pos=0;
  1038.   for (field=form->field, i=1 ; i<= form->fields ; i++,field++)
  1039.   {
  1040.     if ((*field)->offset() == start)
  1041.     {
  1042.       if ((*field)->key_length() == length)
  1043. return (i);
  1044.       if (!pos || form->field[pos-1]->pack_length() <
  1045.   (*field)->pack_length())
  1046. pos=i;
  1047.     }
  1048.   }
  1049.   return (pos);
  1050. }
  1051. /* Check that the integer is in the internvall */
  1052. int set_zone(register int nr, int min_zone, int max_zone)
  1053. {
  1054.   if (nr<=min_zone)
  1055.     return (min_zone);
  1056.   if (nr>=max_zone)
  1057.     return (max_zone);
  1058.   return (nr);
  1059. } /* set_zone */
  1060. /* Adjust number to next larger disk buffer */
  1061. ulong next_io_size(register ulong pos)
  1062. {
  1063.   reg2 ulong offset;
  1064.   if ((offset= pos & (IO_SIZE-1)))
  1065.     return pos-offset+IO_SIZE;
  1066.   return pos;
  1067. } /* next_io_size */
  1068. /*
  1069.   Store an SQL quoted string.
  1070.   SYNOPSIS  
  1071.     append_unescaped()
  1072.     res result String
  1073.     pos string to be quoted
  1074.     length it's length
  1075.   NOTE
  1076.     This function works correctly with utf8 or single-byte charset strings.
  1077.     May fail with some multibyte charsets though.
  1078. */
  1079. void append_unescaped(String *res, const char *pos, uint length)
  1080. {
  1081.   const char *end= pos+length;
  1082.   res->append(''');
  1083.   for (; pos != end ; pos++)
  1084.   {
  1085. #if defined(USE_MB) && MYSQL_VERSION_ID < 40100
  1086.     uint mblen;
  1087.     if (use_mb(default_charset_info) &&
  1088.         (mblen= my_ismbchar(default_charset_info, pos, end)))
  1089.     {
  1090.       res->append(pos, mblen);
  1091.       pos+= mblen;
  1092.       continue;
  1093.     }
  1094. #endif
  1095.     switch (*pos) {
  1096.     case 0: /* Must be escaped for 'mysql' */
  1097.       res->append('\');
  1098.       res->append('0');
  1099.       break;
  1100.     case 'n': /* Must be escaped for logs */
  1101.       res->append('\');
  1102.       res->append('n');
  1103.       break;
  1104.     case 'r':
  1105.       res->append('\'); /* This gives better readbility */
  1106.       res->append('r');
  1107.       break;
  1108.     case '\':
  1109.       res->append('\'); /* Because of the sql syntax */
  1110.       res->append('\');
  1111.       break;
  1112.     case ''':
  1113.       res->append('''); /* Because of the sql syntax */
  1114.       res->append(''');
  1115.       break;
  1116.     default:
  1117.       res->append(*pos);
  1118.       break;
  1119.     }
  1120.   }
  1121.   res->append(''');
  1122. }
  1123. /* Create a .frm file */
  1124. File create_frm(register my_string name,  const char *db, const char *table,
  1125.                 uint reclength, uchar *fileinfo,
  1126. HA_CREATE_INFO *create_info, uint keys)
  1127. {
  1128.   register File file;
  1129.   uint key_length;
  1130.   ulong length;
  1131.   char fill[IO_SIZE];
  1132.   int create_flags= O_RDWR | O_TRUNC;
  1133.   if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
  1134.     create_flags|= O_EXCL | O_NOFOLLOW;
  1135. #if SIZEOF_OFF_T > 4
  1136.   /* Fix this when we have new .frm files;  Current limit is 4G rows (QQ) */
  1137.   if (create_info->max_rows > ~(ulong) 0)
  1138.     create_info->max_rows= ~(ulong) 0;
  1139.   if (create_info->min_rows > ~(ulong) 0)
  1140.     create_info->min_rows= ~(ulong) 0;
  1141. #endif
  1142.   /*
  1143.     Ensure that raid_chunks can't be larger than 255, as this would cause
  1144.     problems with drop database
  1145.   */
  1146.   set_if_smaller(create_info->raid_chunks, 255);
  1147.   if ((file= my_create(name, CREATE_MODE, create_flags, MYF(0))) >= 0)
  1148.   {
  1149.     bzero((char*) fileinfo,64);
  1150.     fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+3; // Header
  1151.     fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
  1152.     fileinfo[4]=1;
  1153.     int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
  1154.     key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
  1155.     length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength));
  1156.     int4store(fileinfo+10,length);
  1157.     if (key_length > 0xffff) key_length=0xffff;
  1158.     int2store(fileinfo+14,key_length);
  1159.     int2store(fileinfo+16,reclength);
  1160.     int4store(fileinfo+18,create_info->max_rows);
  1161.     int4store(fileinfo+22,create_info->min_rows);
  1162.     fileinfo[27]=2; // Use long pack-fields
  1163.     create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
  1164.     int2store(fileinfo+30,create_info->table_options);
  1165.     fileinfo[32]=0; // No filename anymore
  1166.     int4store(fileinfo+34,create_info->avg_row_length);
  1167.     fileinfo[38]= (create_info->default_table_charset ?
  1168.    create_info->default_table_charset->number : 0);
  1169.     fileinfo[40]= (uchar) create_info->row_type;
  1170.     fileinfo[41]= (uchar) create_info->raid_type;
  1171.     fileinfo[42]= (uchar) create_info->raid_chunks;
  1172.     int4store(fileinfo+43,create_info->raid_chunksize);
  1173.     bzero(fill,IO_SIZE);
  1174.     for (; length > IO_SIZE ; length-= IO_SIZE)
  1175.     {
  1176.       if (my_write(file,(byte*) fill,IO_SIZE,MYF(MY_WME | MY_NABP)))
  1177.       {
  1178. VOID(my_close(file,MYF(0)));
  1179. VOID(my_delete(name,MYF(0)));
  1180. return(-1);
  1181.       }
  1182.     }
  1183.   }
  1184.   else
  1185.   {
  1186.     if (my_errno == ENOENT)
  1187.       my_error(ER_BAD_DB_ERROR,MYF(0),db);
  1188.     else
  1189.       my_error(ER_CANT_CREATE_TABLE,MYF(0),table,my_errno);
  1190.   }
  1191.   return (file);
  1192. } /* create_frm */
  1193. void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
  1194. {
  1195.   DBUG_ENTER("update_create_info_from_table");
  1196.   create_info->max_rows=table->max_rows;
  1197.   create_info->min_rows=table->min_rows;
  1198.   create_info->table_options=table->db_create_options;
  1199.   create_info->avg_row_length=table->avg_row_length;
  1200.   create_info->row_type=table->row_type;
  1201.   create_info->raid_type=table->raid_type;
  1202.   create_info->raid_chunks=table->raid_chunks;
  1203.   create_info->raid_chunksize=table->raid_chunksize;
  1204.   create_info->default_table_charset=table->table_charset;
  1205.   create_info->table_charset= 0;
  1206.   DBUG_VOID_RETURN;
  1207. }
  1208. int
  1209. rename_file_ext(const char * from,const char * to,const char * ext)
  1210. {
  1211.   char from_b[FN_REFLEN],to_b[FN_REFLEN];
  1212.   VOID(strxmov(from_b,from,ext,NullS));
  1213.   VOID(strxmov(to_b,to,ext,NullS));
  1214.   return (my_rename(from_b,to_b,MYF(MY_WME)));
  1215. }
  1216. /*
  1217.   Allocate string field in MEM_ROOT and return it as String
  1218.   SYNOPSIS
  1219.     get_field()
  1220.     mem    MEM_ROOT for allocating
  1221.     field  Field for retrieving of string
  1222.     res         result String
  1223.   RETURN VALUES
  1224.     1   string is empty
  1225.     0 all ok
  1226. */
  1227. bool get_field(MEM_ROOT *mem, Field *field, String *res)
  1228. {
  1229.   char buff[MAX_FIELD_WIDTH], *to;
  1230.   String str(buff,sizeof(buff),&my_charset_bin);
  1231.   uint length;
  1232.   field->val_str(&str);
  1233.   if (!(length= str.length()))
  1234.     return 1;
  1235.   to= strmake_root(mem, str.ptr(), length);
  1236.   res->set(to, length, ((Field_str*)field)->charset());
  1237.   return 0;
  1238. }
  1239. /*
  1240.   Allocate string field in MEM_ROOT and return it as NULL-terminated string
  1241.   SYNOPSIS
  1242.     get_field()
  1243.     mem    MEM_ROOT for allocating
  1244.     field  Field for retrieving of string
  1245.   RETURN VALUES
  1246.     NullS  string is empty
  1247.     #      pointer to NULL-terminated string value of field
  1248. */
  1249. char *get_field(MEM_ROOT *mem, Field *field)
  1250. {
  1251.   char buff[MAX_FIELD_WIDTH], *to;
  1252.   String str(buff,sizeof(buff),&my_charset_bin);
  1253.   uint length;
  1254.   field->val_str(&str);
  1255.   length= str.length();
  1256.   if (!length || !(to= (char*) alloc_root(mem,length+1)))
  1257.     return NullS;
  1258.   memcpy(to,str.ptr(),(uint) length);
  1259.   to[length]=0;
  1260.   return to;
  1261. }
  1262. /*
  1263.   Check if database name is valid
  1264.   SYNPOSIS
  1265.     check_db_name()
  1266.     name Name of database
  1267.   NOTES
  1268.     If lower_case_table_names is set then database is converted to lower case
  1269.   RETURN
  1270.     0 ok
  1271.     1   error
  1272. */
  1273. bool check_db_name(char *name)
  1274. {
  1275.   char *start=name;
  1276.   /* Used to catch empty names and names with end space */
  1277.   bool last_char_is_space= TRUE;
  1278.   if (lower_case_table_names && name != any_db)
  1279.     my_casedn_str(files_charset_info, name);
  1280.   while (*name)
  1281.   {
  1282. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1283.     last_char_is_space= my_isspace(default_charset_info, *name);
  1284.     if (use_mb(system_charset_info))
  1285.     {
  1286.       int len=my_ismbchar(system_charset_info, name, 
  1287. name+system_charset_info->mbmaxlen);
  1288.       if (len)
  1289.       {
  1290.         name += len;
  1291.         continue;
  1292.       }
  1293.     }
  1294. #else
  1295.     last_char_is_space= *name==' ';
  1296. #endif
  1297.     if (*name == '/' || *name == '\' || *name == FN_LIBCHAR ||
  1298. *name == FN_EXTCHAR)
  1299.       return 1;
  1300.     name++;
  1301.   }
  1302.   return last_char_is_space || (uint) (name - start) > NAME_LEN;
  1303. }
  1304. /*
  1305.   Allow anything as a table name, as long as it doesn't contain an
  1306.   a '/', or a '.' character
  1307.   or ' ' at the end
  1308.   returns 1 on error
  1309. */
  1310. bool check_table_name(const char *name, uint length)
  1311. {
  1312.   const char *end= name+length;
  1313.   if (!length || length > NAME_LEN)
  1314.     return 1;
  1315. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1316.   bool last_char_is_space= FALSE;
  1317. #else
  1318.   if (name[length-1]==' ')
  1319.     return 1;
  1320. #endif
  1321.   while (name != end)
  1322.   {
  1323. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1324.     last_char_is_space= my_isspace(default_charset_info, *name);
  1325.     if (use_mb(system_charset_info))
  1326.     {
  1327.       int len=my_ismbchar(system_charset_info, name, end);
  1328.       if (len)
  1329.       {
  1330.         name += len;
  1331.         continue;
  1332.       }
  1333.     }
  1334. #endif
  1335.     if (*name == '/' || *name == '\' || *name == FN_EXTCHAR)
  1336.       return 1;
  1337.     name++;
  1338.   }
  1339. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1340.   return last_char_is_space;
  1341. #else
  1342.   return 0;
  1343. #endif
  1344. }
  1345. bool check_column_name(const char *name)
  1346. {
  1347.   const char *start= name;
  1348.   bool last_char_is_space= TRUE;
  1349.   while (*name)
  1350.   {
  1351. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1352.     last_char_is_space= my_isspace(default_charset_info, *name);
  1353.     if (use_mb(system_charset_info))
  1354.     {
  1355.       int len=my_ismbchar(system_charset_info, name, 
  1356. name+system_charset_info->mbmaxlen);
  1357.       if (len)
  1358.       {
  1359.         name += len;
  1360.         continue;
  1361.       }
  1362.     }
  1363. #else
  1364.     last_char_is_space= *name==' ';
  1365. #endif
  1366.     if (*name == NAMES_SEP_CHAR)
  1367.       return 1;
  1368.     name++;
  1369.   }
  1370.   /* Error if empty or too long column name */
  1371.   return last_char_is_space || (uint) (name - start) > NAME_LEN;
  1372. }
  1373. /*
  1374. ** Get type of table from .frm file
  1375. */
  1376. db_type get_table_type(const char *name)
  1377. {
  1378.   File  file;
  1379.   uchar head[4];
  1380.   int error;
  1381.   DBUG_ENTER("get_table_type");
  1382.   DBUG_PRINT("enter",("name: '%s'",name));
  1383.   if ((file=my_open(name,O_RDONLY, MYF(0))) < 0)
  1384.     DBUG_RETURN(DB_TYPE_UNKNOWN);
  1385.   error=my_read(file,(byte*) head,4,MYF(MY_NABP));
  1386.   my_close(file,MYF(0));
  1387.   if (error || head[0] != (uchar) 254 || head[1] != 1 ||
  1388.       (head[2] != FRM_VER && head[2] != FRM_VER+1 && head[2] != FRM_VER+3))
  1389.     DBUG_RETURN(DB_TYPE_UNKNOWN);
  1390.   DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
  1391. }
  1392. /*****************************************************************************
  1393. ** Instansiate templates
  1394. *****************************************************************************/
  1395. #ifdef __GNUC__
  1396. template class List<String>;
  1397. template class List_iterator<String>;
  1398. #endif