home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 January / Chip_2001-01_cd1.bin / tema / mysql / mysql-3.23.28g-win-source.exe / sql / table.cpp < prev    next >
C/C++ Source or Header  |  2000-11-21  |  33KB  |  1,141 lines

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16.  
  17.  
  18. /* Some general useful functions */
  19.  
  20. #include "mysql_priv.h"
  21. #include <errno.h>
  22. #include <m_ctype.h>
  23.  
  24.  
  25.     /* Functions defined in this file */
  26.  
  27. static void frm_error(int error,TABLE *form,const char *name,int errortype);
  28. static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
  29.                   uint types, char **names);
  30. static uint find_field(TABLE *form,uint start,uint length);
  31.  
  32.  
  33. static byte* get_field_name(Field *buff,uint *length,
  34.                 my_bool not_used __attribute__((unused)))
  35. {
  36.   *length= (uint) strlen(buff->field_name);
  37.   return (byte*) buff->field_name;
  38. }
  39.  
  40.     /* Open a .frm file */
  41.  
  42. int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
  43.         uint ha_open_flags, TABLE *outparam)
  44. {
  45.   reg1 uint i;
  46.   reg2 uchar *strpos;
  47.   int     j,error;
  48.   uint     rec_buff_length,n_length,int_length,records,key_parts,keys,
  49.     interval_count,interval_parts,read_length,db_create_options;
  50.   ulong  pos;
  51.   char     index_file[FN_REFLEN], *names,*keynames;
  52.   uchar  head[288],*disk_buff,new_field_pack_flag;
  53.   my_string record;
  54.   const char **int_array;
  55.   bool     new_frm_ver,use_hash, null_field_first;
  56.   File     file;
  57.   Field  **field_ptr,*reg_field;
  58.   KEY     *keyinfo;
  59.   KEY_PART_INFO *key_part;
  60.   uchar *null_pos;
  61.   uint null_bit;
  62.   SQL_CRYPT *crypted=0;
  63.   DBUG_ENTER("openfrm");
  64.   DBUG_PRINT("enter",("name: '%s'  form: %lx",name,outparam));
  65.  
  66.   bzero((char*) outparam,sizeof(*outparam));
  67.   outparam->blob_ptr_size=sizeof(char*);
  68.   disk_buff=NULL; record= NULL; keynames=NullS;
  69.   outparam->db_stat = db_stat;
  70.   error=1;
  71.  
  72.   init_sql_alloc(&outparam->mem_root,1024,0);
  73.   MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
  74.   my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
  75.  
  76.   outparam->real_name=strdup_root(&outparam->mem_root,
  77.                   name+dirname_length(name));
  78.   *fn_ext(outparam->real_name)='\0';        // Remove extension
  79.   outparam->table_name=my_strdup(alias,MYF(MY_WME));
  80.   if (!outparam->real_name || !outparam->table_name)
  81.     goto err_end;
  82.  
  83.   if ((file=my_open(fn_format(index_file,name,"",reg_ext,4),
  84.             O_RDONLY | O_SHARE,
  85.             MYF(0)))
  86.       < 0)
  87.   {
  88.     goto err_end; /* purecov: inspected */
  89.   }
  90.   error=4;
  91.   if (!(outparam->path= strdup_root(&outparam->mem_root,name)))
  92.     goto err_not_open;
  93.   *fn_ext(outparam->path)='\0';        // Remove extension
  94.  
  95.   if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err_not_open;
  96.   if (head[0] != (uchar) 254 || head[1] != 1 ||
  97.       (head[2] != FRM_VER && head[2] != FRM_VER+1))
  98.     goto err_not_open; /* purecov: inspected */
  99.   new_field_pack_flag=head[27];
  100.   new_frm_ver= (head[2] == FRM_VER+1);
  101.  
  102.   error=3;
  103.   if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
  104.     goto err_not_open; /* purecov: inspected */
  105.   *fn_ext(index_file)='\0';            // Remove .frm extension
  106.  
  107.   outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
  108.   outparam->db_create_options=db_create_options=uint2korr(head+30);
  109.   outparam->db_options_in_use=outparam->db_create_options;
  110.   null_field_first=0;
  111.   if (!head[32])                // New frm file in 3.23
  112.   {
  113.     outparam->avg_row_length=uint4korr(head+34);
  114.     outparam->row_type=(row_type) head[40];
  115.     outparam->raid_type=   head[41];
  116.     outparam->raid_chunks= head[42];
  117.     outparam->raid_chunksize= uint4korr(head+43);
  118.     null_field_first=1;
  119.   }
  120.   outparam->db_record_offset=1;
  121.   if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
  122.     outparam->blob_ptr_size=portable_sizeof_char_ptr;
  123.   outparam->db_low_byte_first=test(outparam->db_type == DB_TYPE_MYISAM ||
  124.                    outparam->db_type == DB_TYPE_BERKELEY_DB ||
  125.                    outparam->db_type == DB_TYPE_HEAP);
  126.  
  127.   error=4;
  128.   outparam->max_rows=uint4korr(head+18);
  129.   outparam->min_rows=uint4korr(head+22);
  130.  
  131.   /* Read keyinformation */
  132.   VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
  133.   if (read_string(file,(gptr*) &disk_buff,(uint) uint2korr(head+28)))
  134.     goto err_not_open; /* purecov: inspected */
  135.   outparam->keys=keys=disk_buff[0];
  136.   outparam->keys_in_use= (((key_map) 1) << keys)- (key_map) 1;
  137.  
  138.   outparam->key_parts=key_parts=disk_buff[1];
  139.   n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
  140.   if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
  141.                     n_length+uint2korr(disk_buff+4))))
  142.     goto err_not_open; /* purecov: inspected */
  143.   bzero((char*) keyinfo,n_length);
  144.   outparam->key_info=keyinfo;
  145.   outparam->max_key_length=0;
  146.   key_part= (KEY_PART_INFO*) (keyinfo+keys);
  147.   strpos=disk_buff+6;
  148.  
  149.   ulong *rec_per_key;
  150.   if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root,
  151.                      sizeof(ulong*)*key_parts)))
  152.     goto err_not_open;
  153.  
  154.   for (i=0 ; i < keys ; i++, keyinfo++)
  155.   {
  156.     uint null_parts=0;
  157.     keyinfo->flags=     ((uint) strpos[0]) ^ HA_NOSAME;
  158.     keyinfo->key_length= (uint) uint2korr(strpos+1);
  159.     keyinfo->key_parts=  (uint) strpos[3];  strpos+=4;
  160.     keyinfo->key_part=     key_part;
  161.     keyinfo->rec_per_key= rec_per_key;
  162.     for (j=keyinfo->key_parts ; j-- ; key_part++)
  163.     {
  164.       *rec_per_key++=0;
  165.       key_part->fieldnr=    (uint16) (uint2korr(strpos) & FIELD_NR_MASK);
  166.       key_part->offset= (uint) uint2korr(strpos+2)-1;
  167.       key_part->key_type=    (uint) uint2korr(strpos+5);
  168.       // key_part->field=    (Field*) 0;    // Will be fixed later
  169.       if (new_frm_ver)
  170.       {
  171.     key_part->key_part_flag= *(strpos+4);
  172.     key_part->length=    (uint) uint2korr(strpos+7);
  173.     strpos+=9;
  174.       }
  175.       else
  176.       {
  177.     key_part->length=    *(strpos+4);
  178.     key_part->key_part_flag=0;
  179.     if (key_part->length > 128)
  180.     {
  181.       key_part->length&=127;        /* purecov: inspected */
  182.       key_part->key_part_flag=HA_REVERSE_SORT; /* purecov: inspected */
  183.     }
  184.     strpos+=7;
  185.       }
  186.       key_part->store_length=key_part->length;
  187.     }
  188.     keyinfo->key_length+=null_parts;
  189.     set_if_bigger(outparam->max_key_length,keyinfo->key_length+
  190.           keyinfo->key_parts);
  191.     if (keyinfo->flags & HA_NOSAME)
  192.       set_if_bigger(outparam->max_unique_length,keyinfo->key_length);
  193.   }
  194.  
  195.   (void) strmov(keynames= (char *) key_part,(char *) strpos);
  196.   outparam->reclength = uint2korr((head+16));
  197.   if (*(head+26) == 1)
  198.     outparam->system=1;                /* one-record-database */
  199. #ifdef HAVE_CRYPTED_FRM
  200.   else if (*(head+26) == 2)
  201.   {
  202.     extern SQL_CRYPT *get_crypt_for_frm(void);
  203.     my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  204.     crypted=get_crypt_for_frm();
  205.     my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
  206.     outparam->crypted=1;
  207.   }
  208. #endif
  209.  
  210.   /* Allocate handler */
  211.   if (!(outparam->file= get_new_handler(outparam,outparam->db_type)))
  212.     goto err_not_open;
  213.  
  214.   error=4;
  215.   outparam->reginfo.lock_type= TL_UNLOCK;
  216.   outparam->current_lock=F_UNLCK;
  217.   if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) records=2;
  218.   else records=1;
  219.   if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
  220.   /* QQ: TODO, remove the +1 from below */
  221.   rec_buff_length=ALIGN_SIZE(outparam->reclength+1+
  222.                  outparam->file->extra_rec_buf_length());
  223.   if (!(outparam->record[0]= (byte*)
  224.     (record = (char *) alloc_root(&outparam->mem_root,
  225.                       rec_buff_length * records))))
  226.     goto err_not_open;                /* purecov: inspected */
  227.   record[outparam->reclength]=0;        // For purify and ->c_ptr()
  228.   outparam->rec_buff_length=rec_buff_length;
  229.   if (my_pread(file,(byte*) record,(uint) outparam->reclength,
  230.            (ulong) (uint2korr(head+6)+uint2korr(head+14)),
  231.            MYF(MY_NABP)))
  232.     goto err_not_open; /* purecov: inspected */
  233.   for (i=0 ; i < records ; i++, record+=rec_buff_length)
  234.   {
  235.     outparam->record[i]=(byte*) record;
  236.     if (i)
  237.       memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
  238.   }
  239.  
  240.   if (records == 2)
  241.   {                        /* fix for select */
  242.     outparam->record[2]=outparam->record[1];
  243.     if (db_stat & HA_READ_ONLY)
  244.       outparam->record[1]=outparam->record[0]; /* purecov: inspected */
  245.   }
  246.  
  247.   VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
  248.   if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
  249.   if (crypted)
  250.   {
  251.     crypted->decode((char*) head+256,288-256);
  252.     if (sint2korr(head+284) != 0)        // Should be 0
  253.       goto err_not_open;            // Wrong password
  254.   }
  255.  
  256.   outparam->fields= uint2korr(head+258);
  257.   pos=uint2korr(head+260);            /* Length of all screens */
  258.   n_length=uint2korr(head+268);
  259.   interval_count=uint2korr(head+270);
  260.   interval_parts=uint2korr(head+272);
  261.   int_length=uint2korr(head+274);
  262.   outparam->null_fields=uint2korr(head+282);
  263.   outparam->comment=strdup_root(&outparam->mem_root,
  264.                 (char*) head+47);
  265.  
  266.   DBUG_PRINT("form",("i_count: %d  i_parts: %d  index: %d  n_length: %d  int_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length));
  267.  
  268.   if (!(field_ptr = (Field **)
  269.     alloc_root(&outparam->mem_root,
  270.            (uint) ((outparam->fields+1)*sizeof(Field*)+
  271.                interval_count*sizeof(TYPELIB)+
  272.                (outparam->fields+interval_parts+
  273.                 keys+3)*sizeof(my_string)+
  274.                (n_length+int_length)))))
  275.     goto err_not_open; /* purecov: inspected */
  276.  
  277.   outparam->field=field_ptr;
  278.   read_length=((uint) (outparam->fields*11)+pos+
  279.            (uint) (n_length+int_length));
  280.   if (read_string(file,(gptr*) &disk_buff,read_length))
  281.     goto err_not_open; /* purecov: inspected */
  282.   if (crypted)
  283.   {
  284.     crypted->decode((char*) disk_buff,read_length);
  285.     delete crypted;
  286.     crypted=0;
  287.   }
  288.   strpos= disk_buff+pos;
  289.  
  290.   outparam->intervals= (TYPELIB*) (field_ptr+outparam->fields+1);
  291.   int_array= (const char **) (outparam->intervals+interval_count);
  292.   names= (char*) (int_array+outparam->fields+interval_parts+keys+3);
  293.   if (!interval_count)
  294.     outparam->intervals=0;            // For better debugging
  295.   memcpy((char*) names, strpos+(outparam->fields*11),
  296.      (uint) (n_length+int_length));
  297.  
  298.   fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
  299.   fix_type_pointers(&int_array,outparam->intervals,interval_count,
  300.             &names);
  301.   if (keynames)
  302.     fix_type_pointers(&int_array,&outparam->keynames,1,&keynames);
  303.   VOID(my_close(file,MYF(MY_WME)));
  304.   file= -1;
  305.  
  306.   record=(char*) outparam->record[0]-1;        /* Fieldstart = 1 */
  307.   if (null_field_first)
  308.   {
  309.     outparam->null_flags=null_pos=(uchar*) record+1;
  310.     null_bit= (db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
  311.     outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
  312.   }
  313.   else
  314.   {
  315.     outparam->null_bytes=(outparam->null_fields+7)/8;
  316.     outparam->null_flags=null_pos=
  317.       (uchar*) (record+1+outparam->reclength-outparam->null_bytes);
  318.     null_bit=1;
  319.   }
  320.  
  321.   use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
  322.   if (use_hash)
  323.     use_hash= !hash_init(&outparam->name_hash,
  324.              outparam->fields,0,0,
  325.              (hash_get_key) get_field_name,0,
  326.              HASH_CASE_INSENSITIVE);
  327.  
  328.   for (i=0 ; i < outparam->fields; i++, strpos+= 11, field_ptr++)
  329.   {
  330.     uint pack_flag= uint2korr(strpos+6);
  331.     uint interval_nr= (uint) strpos[10];
  332.  
  333.     *field_ptr=reg_field=
  334.       make_field(record+uint2korr(strpos+4),
  335.          (uint32) strpos[3],        // field_length
  336.          null_pos,null_bit,
  337.          pack_flag,
  338.          (Field::utype) MTYP_TYPENR((uint) strpos[8]),
  339.          (interval_nr ?
  340.           outparam->intervals+interval_nr-1 :
  341.           (TYPELIB*) 0),
  342.          outparam->fieldnames.type_names[i],
  343.          outparam);
  344.     if (!(reg_field->flags & NOT_NULL_FLAG))
  345.     {
  346.       if ((null_bit<<=1) == 256)
  347.       {
  348.     null_pos++;
  349.     null_bit=1;
  350.       }
  351.     }
  352.     if (reg_field->unireg_check == Field::NEXT_NUMBER)
  353.     {
  354.       if ((int) (outparam->next_number_index= (uint)
  355.          find_ref_key(outparam,reg_field,
  356.                   &outparam->next_number_key_offset)) < 0)
  357.     reg_field->unireg_check=Field::NONE;    /* purecov: inspected */
  358.       else
  359.       {
  360.     outparam->found_next_number_field=reg_field;
  361.     reg_field->flags|=AUTO_INCREMENT_FLAG;
  362.       }
  363.     }
  364.     if (outparam->timestamp_field == reg_field)
  365.       outparam->timestamp_field_offset=i;
  366.     if (use_hash)
  367.       (void) hash_insert(&outparam->name_hash,(byte*) *field_ptr); // Will never fail
  368.   }
  369.   *field_ptr=0;                    // End marker
  370.  
  371.   /* Fix key->name and key_part->field */
  372.   if (key_parts)
  373.   {
  374.     uint primary_key=(uint) (find_type((char*) "PRIMARY",&outparam->keynames,
  375.                        3)-1);
  376.     uint ha_option=outparam->file->option_flag();
  377.     keyinfo=outparam->key_info;
  378.     key_part=keyinfo->key_part;
  379.  
  380.     for (uint key=0 ; key < outparam->keys ; key++,keyinfo++)
  381.     {
  382.       uint usable_parts=0;
  383.       keyinfo->name=(char*) outparam->keynames.type_names[key];
  384.       if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
  385.       {
  386.     /*
  387.       If the UNIQUE key don't have NULL columns, declare this as
  388.       a primary key.
  389.     */
  390.     primary_key=key;
  391.     for (i=0 ; i < keyinfo->key_parts ;i++)
  392.     {
  393.       if (!key_part[i].fieldnr ||
  394.           outparam->field[key_part[i].fieldnr-1]->null_ptr)
  395.       {
  396.         primary_key=MAX_KEY;        // Can't be used
  397.         break;
  398.       }
  399.     }
  400.       }
  401.  
  402.       for (i=0 ; i < keyinfo->key_parts ; key_part++,i++)
  403.       {
  404.     if (new_field_pack_flag <= 1)
  405.       key_part->fieldnr=(uint16) find_field(outparam,
  406.                         (uint) key_part->offset,
  407.                         (uint) key_part->length);
  408. #ifdef EXTRA_DEBUG
  409.     if (key_part->fieldnr > outparam->fields)
  410.       goto err_not_open; // sanity check
  411. #endif
  412.     if (key_part->fieldnr)
  413.     {                    // Should always be true !
  414.       Field *field=key_part->field=outparam->field[key_part->fieldnr-1];
  415.       if (field->null_ptr)
  416.       {
  417.         key_part->null_offset=(uint) ((byte*) field->null_ptr -
  418.                       outparam->record[0]);
  419.         key_part->null_bit= field->null_bit;
  420.         key_part->store_length+=HA_KEY_NULL_LENGTH;
  421.         keyinfo->flags|=HA_NULL_PART_KEY;
  422.         keyinfo->extra_length+= HA_KEY_NULL_LENGTH;
  423.       }
  424.       if (field->type() == FIELD_TYPE_BLOB ||
  425.           field->real_type() == FIELD_TYPE_VAR_STRING)
  426.       {
  427.         if (field->type() == FIELD_TYPE_BLOB)
  428.           key_part->key_part_flag|= HA_BLOB_PART;
  429.         keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
  430.         key_part->store_length+=HA_KEY_BLOB_LENGTH;
  431.       }
  432.       if (i == 0 && key != primary_key)
  433.         field->flags |=
  434.           ((keyinfo->flags & HA_NOSAME) &&
  435.            field->key_length() ==
  436.            keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
  437.       if (i == 0)
  438.         field->key_start|= ((key_map) 1 << key);
  439.       if ((ha_option & HA_HAVE_KEY_READ_ONLY) &&
  440.           field->key_length() == key_part->length &&
  441.           field->type() != FIELD_TYPE_BLOB &&
  442.           (field->key_type() != HA_KEYTYPE_TEXT ||
  443.            (!(ha_option & HA_KEY_READ_WRONG_STR) &&
  444.         !(keyinfo->flags & HA_FULLTEXT))))
  445.         field->part_of_key|= ((key_map) 1 << key);
  446.       if (!(key_part->key_part_flag & HA_REVERSE_SORT) &&
  447.           usable_parts == i)
  448.         usable_parts++;            // For FILESORT
  449.       field->flags|= PART_KEY_FLAG;
  450.       if (key == primary_key)
  451.       {
  452.         field->flags|= PRI_KEY_FLAG;
  453.         if (ha_option & HA_PRIMARY_KEY_IN_READ_INDEX)
  454.           field->part_of_key|= ((key_map) 1 << primary_key);
  455.       }
  456.       if (field->key_length() != key_part->length)
  457.       {
  458.         key_part->key_part_flag|= HA_PART_KEY;
  459.         if (field->type() != FIELD_TYPE_BLOB)
  460.         {                    // Create a new field
  461.           field=key_part->field=field->new_field(outparam);
  462.           field->field_length=key_part->length;
  463.         }
  464.       }
  465.     }
  466.     else
  467.     {                    // Error: shorten key
  468.       keyinfo->key_parts=usable_parts;
  469.       keyinfo->flags=0;
  470.     }
  471.       }
  472.       keyinfo->usable_key_parts=usable_parts; // Filesort
  473.     }
  474.     if (primary_key < MAX_KEY && 
  475.     (outparam->keys_in_use & ((key_map) 1 << primary_key)))
  476.     {
  477.       outparam->primary_key=primary_key;
  478.       if (outparam->file->option_flag() & HA_PRIMARY_KEY_IN_READ_INDEX)
  479.     outparam->ref_primary_key= (key_map) 1 << primary_key;
  480.       /*
  481.     If we are using an integer as the primary key then allow the user to
  482.     refer to it as '_rowid'
  483.       */
  484.       if (outparam->key_info[primary_key].key_parts == 1)
  485.       {
  486.     Field *field= outparam->key_info[primary_key].key_part[0].field;
  487.     if (field && field->result_type() == INT_RESULT)
  488.       outparam->rowid_field=field;
  489.       }
  490.     }
  491.     else
  492.       outparam->primary_key = MAX_KEY; // we do not have a primary key
  493.   }
  494.   else
  495.     outparam->primary_key= MAX_KEY;
  496.   x_free((gptr) disk_buff);
  497.   disk_buff=0;
  498.   if (new_field_pack_flag <= 1)
  499.   {            /* Old file format with default null */
  500.     uint null_length=(outparam->null_fields+7)/8;
  501.     bfill(outparam->null_flags,null_length,255);
  502.     bfill(outparam->null_flags+outparam->rec_buff_length,null_length,255);
  503.     if (records > 2)
  504.       bfill(outparam->null_flags+outparam->rec_buff_length*2,null_length,255);
  505.   }
  506.  
  507.   if (outparam->blob_fields)
  508.   {
  509.     Field **ptr;
  510.     Field_blob **save;
  511.  
  512.     if (!(outparam->blob_field=save=
  513.       (Field_blob**) alloc_root(&outparam->mem_root,
  514.                     (uint) (outparam->blob_fields+1)*
  515.                     sizeof(Field_blob*))))
  516.       goto err_not_open;
  517.     for (ptr=outparam->field ; *ptr ; ptr++)
  518.     {
  519.       if ((*ptr)->flags & BLOB_FLAG)
  520.     (*save++)= (Field_blob*) *ptr;
  521.     }
  522.     *save=0;                    // End marker
  523.   }
  524.   else
  525.     outparam->blob_field=
  526.       (Field_blob**) (outparam->field+outparam->fields); // Point at null ptr
  527.  
  528.   /* The table struct is now initialzed;  Open the table */
  529.   error=2;
  530.   if (db_stat)
  531.   {
  532.     int err;
  533.     if ((err=(outparam->file->
  534.           ha_open(index_file,
  535.               (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
  536.               (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
  537.                ((db_stat & HA_WAIT_IF_LOCKED) ||
  538.             (specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
  539.                HA_OPEN_WAIT_IF_LOCKED :
  540.                (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
  541.                HA_OPEN_ABORT_IF_LOCKED :
  542.                HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
  543.     {
  544.       /* Set a flag if the table is crashed and it can be auto. repaired */
  545.       outparam->crashed=((err == HA_ERR_CRASHED_ON_USAGE) &&
  546.              outparam->file->auto_repair() &&
  547.              !(ha_open_flags & HA_OPEN_FOR_REPAIR));
  548.       goto err_not_open; /* purecov: inspected */
  549.     }
  550.   }
  551.   outparam->db_low_byte_first=outparam->file->low_byte_first();
  552.  
  553.   my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  554.   opened_tables++;
  555. #ifndef DBUG_OFF
  556.   if (use_hash)
  557.     (void) hash_check(&outparam->name_hash);
  558. #endif
  559.   DBUG_RETURN (0);
  560.  
  561.  err_not_open:
  562.   x_free((gptr) disk_buff);
  563.   if (file > 0)
  564.     VOID(my_close(file,MYF(MY_WME)));
  565.  
  566.  err_end:                    /* Here when no file */
  567.   delete crypted;
  568.   my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  569.   frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG);
  570.   delete outparam->file;
  571.   outparam->file=0;                // For easyer errorchecking
  572.   outparam->db_stat=0;
  573.   free_root(&outparam->mem_root,MYF(0));
  574.   my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
  575.   DBUG_RETURN (error);
  576. } /* openfrm */
  577.  
  578.  
  579.     /* close a .frm file and it's tables */
  580.  
  581. int closefrm(register TABLE *table)
  582. {
  583.   int error=0;
  584.   DBUG_ENTER("closefrm");
  585.   if (table->db_stat)
  586.     error=table->file->close();
  587.   if (table->table_name)
  588.   {
  589.     my_free(table->table_name,MYF(0));
  590.     table->table_name=0;
  591.   }
  592.   if (table->fields)
  593.   {
  594.     for (Field **ptr=table->field ; *ptr ; ptr++)
  595.       delete *ptr;
  596.     table->fields=0;
  597.   }
  598.   delete table->file;
  599.   table->file=0;                /* For easyer errorchecking */
  600.   hash_free(&table->name_hash);
  601.   free_root(&table->mem_root,MYF(0));
  602.   DBUG_RETURN(error);
  603. }
  604.  
  605.  
  606. /* Deallocate temporary blob storage */
  607.  
  608. void free_blobs(register TABLE *table)
  609. {
  610.   for (Field_blob **ptr=table->blob_field ; *ptr ; ptr++)
  611.     (*ptr)->free();
  612. }
  613.  
  614.  
  615.     /* Find where a form starts */
  616.     /* if formname is NullS then only formnames is read */
  617.  
  618. ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
  619. {
  620.   uint a_length,names,length;
  621.   uchar *pos,*buf;
  622.   ulong ret_value=0;
  623.   DBUG_ENTER("get_form_pos");
  624.  
  625.   names=uint2korr(head+8);
  626.   a_length=(names+2)*sizeof(my_string);        /* Room for two extra */
  627.  
  628.   if (!save_names)
  629.     a_length=0;
  630.   else
  631.     save_names->type_names=0;            /* Clear if error */
  632.  
  633.   if (names)
  634.   {
  635.     length=uint2korr(head+4);
  636.     VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0)));
  637.     if (!(buf= (uchar*) my_malloc((uint) length+a_length+names*4,
  638.                   MYF(MY_WME))) ||
  639.     my_read(file,(byte*) buf+a_length,(uint) (length+names*4),
  640.         MYF(MY_NABP)))
  641.     {                        /* purecov: inspected */
  642.       x_free((gptr) buf);            /* purecov: inspected */
  643.       DBUG_RETURN(0L);                /* purecov: inspected */
  644.     }
  645.     pos= buf+a_length+length;
  646.     ret_value=uint4korr(pos);
  647.   }
  648.   if (! save_names)
  649.     my_free((gptr) buf,MYF(0));
  650.   else if (!names)
  651.     bzero((char*) save_names,sizeof(save_names));
  652.   else
  653.   {
  654.     char *str;
  655.     str=(char *) (buf+a_length);
  656.     fix_type_pointers((const char ***) &buf,save_names,1,&str);
  657.   }
  658.   DBUG_RETURN(ret_value);
  659. }
  660.  
  661.  
  662.     /* Read string from a file with malloc */
  663.  
  664. int read_string(File file, gptr *to, uint length)
  665. {
  666.   DBUG_ENTER("read_string");
  667.  
  668.   x_free((gptr) *to);
  669.   if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
  670.       my_read(file,(byte*) *to,length,MYF(MY_NABP)))
  671.   {
  672.     x_free((gptr) *to); /* purecov: inspected */
  673.     *to= 0; /* purecov: inspected */
  674.     DBUG_RETURN(1); /* purecov: inspected */
  675.   }
  676.   *((char*) *to+length)= '\0';
  677.   DBUG_RETURN (0);
  678. } /* read_string */
  679.  
  680.  
  681.     /* Add a new form to a form file */
  682.  
  683. ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
  684.              const char *newname)
  685. {
  686.   uint i,bufflength,maxlength,n_length,length,names;
  687.   ulong endpos,newpos;
  688.   char buff[IO_SIZE];
  689.   uchar *pos;
  690.   DBUG_ENTER("make_new_entry");
  691.  
  692.   length=(uint) strlen(newname)+1;
  693.   n_length=uint2korr(fileinfo+4);
  694.   maxlength=uint2korr(fileinfo+6);
  695.   names=uint2korr(fileinfo+8);
  696.   newpos=uint4korr(fileinfo+10);
  697.  
  698.   if (64+length+n_length+(names+1)*4 > maxlength)
  699.   {                        /* Expand file */
  700.     newpos+=IO_SIZE;
  701.     int4store(fileinfo+10,newpos);
  702.     endpos=(ulong) my_seek(file,0L,MY_SEEK_END,MYF(0));/* Copy from file-end */
  703.     bufflength= (uint) (endpos & (IO_SIZE-1));    /* IO_SIZE is a power of 2 */
  704.  
  705.     while (endpos > maxlength)
  706.     {
  707.       VOID(my_seek(file,(ulong) (endpos-bufflength),MY_SEEK_SET,MYF(0)));
  708.       if (my_read(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
  709.     DBUG_RETURN(0L);
  710.       VOID(my_seek(file,(ulong) (endpos-bufflength+IO_SIZE),MY_SEEK_SET,
  711.            MYF(0)));
  712.       if ((my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME))))
  713.     DBUG_RETURN(0);
  714.       endpos-=bufflength; bufflength=IO_SIZE;
  715.     }
  716.     bzero(buff,IO_SIZE);            /* Null new block */
  717.     VOID(my_seek(file,(ulong) maxlength,MY_SEEK_SET,MYF(0)));
  718.     if (my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
  719.     DBUG_RETURN(0L);
  720.     maxlength+=IO_SIZE;                /* Fix old ref */
  721.     int2store(fileinfo+6,maxlength);
  722.     for (i=names, pos= (uchar*) *formnames->type_names+n_length-1; i-- ;
  723.      pos+=4)
  724.     {
  725.       endpos=uint4korr(pos)+IO_SIZE;
  726.       int4store(pos,endpos);
  727.     }
  728.   }
  729.  
  730.   if (n_length == 1 )
  731.   {                        /* First name */
  732.     length++;
  733.     VOID(strxmov(buff,"/",newname,"/",NullS));
  734.   }
  735.   else
  736.     VOID(strxmov(buff,newname,"/",NullS)); /* purecov: inspected */
  737.   VOID(my_seek(file,63L+(ulong) n_length,MY_SEEK_SET,MYF(0)));
  738.   if (my_write(file,(byte*) buff,(uint) length+1,MYF(MY_NABP+MY_WME)) ||
  739.       (names && my_write(file,(byte*) (*formnames->type_names+n_length-1),
  740.              names*4, MYF(MY_NABP+MY_WME))) ||
  741.       my_write(file,(byte*) fileinfo+10,(uint) 4,MYF(MY_NABP+MY_WME)))
  742.     DBUG_RETURN(0L); /* purecov: inspected */
  743.  
  744.   int2store(fileinfo+8,names+1);
  745.   int2store(fileinfo+4,n_length+length);
  746.   VOID(my_chsize(file,newpos,MYF(MY_WME)));    /* Append file with '\0' */
  747.   DBUG_RETURN(newpos);
  748. } /* make_new_entry */
  749.  
  750.  
  751.     /* error message when opening a form file */
  752.  
  753. static void frm_error(int error, TABLE *form, const char *name, myf errortype)
  754. {
  755.   int err_no;
  756.   char buff[FN_REFLEN];
  757.   const char *form_dev="",*datext;
  758.   DBUG_ENTER("frm_error");
  759.  
  760.   switch (error) {
  761.   case 1:
  762.     if (my_errno == ENOENT)
  763.     {
  764.       char *db;
  765.       uint length=dirname_part(buff,name);
  766.       buff[length-1]=0;
  767.       db=buff+dirname_length(buff);
  768.       my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->real_name);
  769.     }
  770.     else
  771.       my_error(ER_FILE_NOT_FOUND,errortype,
  772.            fn_format(buff,name,form_dev,reg_ext,0),my_errno);
  773.     break;
  774.   case 2:
  775.   {
  776.     datext=form->file ? *form->file->bas_ext() : "";
  777.     err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
  778.       ER_FILE_USED : ER_CANT_OPEN_FILE;
  779.     my_error(err_no,errortype,
  780.          fn_format(buff,form->real_name,form_dev,datext,2),my_errno);
  781.     break;
  782.   }
  783.   default:                /* Better wrong error than none */
  784.   case 4:
  785.     my_error(ER_NOT_FORM_FILE,errortype,
  786.          fn_format(buff,name,form_dev,reg_ext,0));
  787.     break;
  788.   }
  789.   DBUG_VOID_RETURN;
  790. } /* frm_error */
  791.  
  792.  
  793.     /*
  794.     ** fix a str_type to a array type
  795.     ** typeparts sepearated with some char. differents types are separated
  796.     ** with a '\0'
  797.     */
  798.  
  799. static void
  800. fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types,
  801.           char **names)
  802. {
  803.   char *type_name, *ptr;
  804.   char chr;
  805.  
  806.   ptr= *names;
  807.   while (types--)
  808.   {
  809.     point_to_type->name=0;
  810.     point_to_type->type_names= *array;
  811.  
  812.     if ((chr= *ptr))            /* Test if empty type */
  813.     {
  814.       while ((type_name=strchr(ptr+1,chr)) != NullS)
  815.       {
  816.     *((*array)++) = ptr+1;
  817.     *type_name= '\0';        /* End string */
  818.     ptr=type_name;
  819.       }
  820.       ptr+=2;                /* Skipp end mark and last 0 */
  821.     }
  822.     else
  823.       ptr++;
  824.     point_to_type->count= (uint) (*array - point_to_type->type_names);
  825.     point_to_type++;
  826.     *((*array)++)= NullS;        /* End of type */
  827.   }
  828.   *names=ptr;                /* Update end */
  829.   return;
  830. } /* fix_type_pointers */
  831.  
  832.  
  833. TYPELIB *typelib(List<String> &strings)
  834. {
  835.   TYPELIB *result=(TYPELIB*) sql_alloc(sizeof(TYPELIB));
  836.   if (!result)
  837.     return 0;
  838.   result->count=strings.elements;
  839.   result->name="";
  840.   if (!(result->type_names=(const char **) sql_alloc(sizeof(char *)*
  841.                              (result->count+1))))
  842.     return 0;
  843.   List_iterator<String> it(strings);
  844.   String *tmp;
  845.   for (uint i=0; (tmp=it++) ; i++)
  846.     result->type_names[i]=tmp->ptr();
  847.   result->type_names[result->count]=0;        // End marker
  848.   return result;
  849. }
  850.  
  851.  
  852.     /*
  853.     ** Search after a field with given start & length
  854.     ** If an exact field isn't found, return longest field with starts
  855.     ** at right position.
  856.     ** Return 0 on error, else field number+1
  857.     ** This is needed because in some .frm fields 'fieldnr' was saved wrong
  858.     */
  859.  
  860. static uint find_field(TABLE *form,uint start,uint length)
  861. {
  862.   Field **field;
  863.   uint i,pos;
  864.  
  865.   pos=0;
  866.  
  867.   for (field=form->field, i=1 ; i<= form->fields ; i++,field++)
  868.   {
  869.     if ((*field)->offset() == start)
  870.     {
  871.       if ((*field)->key_length() == length)
  872.     return (i);
  873.       if (!pos || form->field[pos-1]->pack_length() <
  874.       (*field)->pack_length())
  875.     pos=i;
  876.     }
  877.   }
  878.   return (pos);
  879. }
  880.  
  881.  
  882.     /* Check that the integer is in the internvall */
  883.  
  884. int set_zone(register int nr, int min_zone, int max_zone)
  885. {
  886.   if (nr<=min_zone)
  887.     return (min_zone);
  888.   if (nr>=max_zone)
  889.     return (max_zone);
  890.   return (nr);
  891. } /* set_zone */
  892.  
  893.     /* Adjust number to next larger disk buffer */
  894.  
  895. ulong next_io_size(register ulong pos)
  896. {
  897.   reg2 ulong offset;
  898.   if ((offset= pos & (IO_SIZE-1)))
  899.     return pos-offset+IO_SIZE;
  900.   return pos;
  901. } /* next_io_size */
  902.  
  903.  
  904. void append_unescaped(String *res,const char *pos)
  905. {
  906.   for ( ; *pos ; pos++)
  907.   {
  908.     switch (*pos) {
  909.     case 0:                /* Must be escaped for 'mysql' */
  910.       res->append('\\');
  911.       res->append('0');
  912.       break;
  913.     case '\n':                /* Must be escaped for logs */
  914.       res->append('\\');
  915.       res->append('n');
  916.       break;
  917.     case '\r':
  918.       res->append('\\');        /* This gives better readbility */
  919.       res->append('r');
  920.       break;
  921.     case '\\':
  922.       res->append('\\');        /* Because of the sql syntax */
  923.       res->append('\\');
  924.       break;
  925.     case '\'':
  926.       res->append('\'');        /* Because of the sql syntax */
  927.       res->append('\'');
  928.       break;
  929.     default:
  930.       res->append(*pos);
  931.       break;
  932.     }
  933.   }
  934. }
  935.  
  936.     /* Create a .frm file */
  937.  
  938. File create_frm(register my_string name, uint reclength, uchar *fileinfo,
  939.         HA_CREATE_INFO *create_info, uint keys)
  940. {
  941.   register File file;
  942.   uint key_length;
  943.   ulong length;
  944.   char fill[IO_SIZE];
  945.  
  946. #if SIZEOF_OFF_T > 4
  947.   /* Fix this in MySQL 4.0;  The current limit is 4G rows (QQ) */
  948.   if (create_info->max_rows > ~(ulong) 0)
  949.     create_info->max_rows= ~(ulong) 0;
  950.   if (create_info->min_rows > ~(ulong) 0)
  951.     create_info->min_rows= ~(ulong) 0;
  952. #endif
  953.  
  954.   if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
  955.   {
  956.     bzero((char*) fileinfo,64);
  957.     fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+1; // Header
  958.     fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
  959.     fileinfo[4]=1;
  960.     int2store(fileinfo+6,IO_SIZE);        /* Next block starts here */
  961.     key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
  962.     length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength));
  963.     int4store(fileinfo+10,length);
  964.     int2store(fileinfo+14,key_length);
  965.     int2store(fileinfo+16,reclength);
  966.     int4store(fileinfo+18,create_info->max_rows);
  967.     int4store(fileinfo+22,create_info->min_rows);
  968.     fileinfo[27]=2;                // Use long pack-fields
  969.     create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers
  970.     int2store(fileinfo+30,create_info->table_options);
  971.     fileinfo[32]=0;                // No filename anymore
  972.     int4store(fileinfo+34,create_info->avg_row_length);
  973.     fileinfo[40]= (uchar) create_info->row_type;
  974.     fileinfo[41]= (uchar) create_info->raid_type;
  975.     fileinfo[42]= (uchar) create_info->raid_chunks;
  976.     int4store(fileinfo+43,create_info->raid_chunksize);
  977.     bzero(fill,IO_SIZE);
  978.     for (; length > IO_SIZE ; length-= IO_SIZE)
  979.     {
  980.       if (my_write(file,(byte*) fill,IO_SIZE,MYF(MY_WME | MY_NABP)))
  981.       {
  982.     VOID(my_close(file,MYF(0)));
  983.     VOID(my_delete(name,MYF(0)));
  984.     return(-1);
  985.       }
  986.     }
  987.   }
  988.   return (file);
  989. } /* create_frm */
  990.  
  991.  
  992. void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
  993. {
  994.   create_info->max_rows=table->max_rows;
  995.   create_info->min_rows=table->min_rows;
  996.   create_info->table_options=table->db_create_options;
  997.   create_info->avg_row_length=table->avg_row_length;
  998.   create_info->row_type=table->row_type;
  999.   create_info->raid_type=table->raid_type;
  1000.   create_info->raid_chunks=table->raid_chunks;
  1001.   create_info->raid_chunksize=table->raid_chunksize;
  1002. }  
  1003.  
  1004. int
  1005. rename_file_ext(const char * from,const char * to,const char * ext)
  1006. {
  1007.   char from_b[FN_REFLEN],to_b[FN_REFLEN];
  1008.   VOID(strxmov(from_b,from,ext,NullS));
  1009.   VOID(strxmov(to_b,to,ext,NullS));
  1010.   return (my_rename(from_b,to_b,MYF(MY_WME)));
  1011. }
  1012.  
  1013.  
  1014. /*
  1015.   Alloc a value as a string and return it
  1016.   If field is empty, return NULL
  1017. */
  1018.  
  1019. char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr)
  1020. {
  1021.   Field *field=table->field[fieldnr];
  1022.   char buff[MAX_FIELD_WIDTH];
  1023.   String str(buff,sizeof(buff));
  1024.   field->val_str(&str,&str);
  1025.   uint length=str.length();
  1026.   if (!length)
  1027.     return NullS;
  1028.   char *to= (char*) alloc_root(mem,length+1);
  1029.   memcpy(to,str.ptr(),(uint) length);
  1030.   to[length]=0;
  1031.   return to;
  1032. }
  1033.  
  1034. bool check_db_name(const char *name)
  1035. {
  1036.   while (*name)
  1037.   {
  1038. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1039.     if (use_mb(default_charset_info))
  1040.     {
  1041.       int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
  1042.       if (len)
  1043.       {
  1044.         name += len;
  1045.         continue;
  1046.       }
  1047.     }
  1048. #endif
  1049.     if (*name == '/' || *name == FN_LIBCHAR)
  1050.       return 1;
  1051.     name++;
  1052.   }
  1053.   return 0;
  1054. }
  1055.  
  1056.  
  1057. /*
  1058.   Allow anything as a table name, as long as it doesn't contain an
  1059.   a '/', or a '.' character
  1060.   returns 1 on error
  1061. */
  1062.  
  1063.  
  1064. bool check_table_name(const char *name, uint length)
  1065. {
  1066.   const char *end= name+length;
  1067.  
  1068.   while (name != end)
  1069.   {
  1070. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1071.     if (use_mb(default_charset_info))
  1072.     {
  1073.       int len=my_ismbchar(default_charset_info, name, end);
  1074.       if (len)
  1075.       {
  1076.         name += len;
  1077.         continue;
  1078.       }
  1079.     }
  1080. #endif
  1081.     if (*name == '/' || *name == FN_LIBCHAR || *name == FN_EXTCHAR)
  1082.       return 1;
  1083.     name++;
  1084.   }
  1085.   return 0;
  1086. }
  1087.  
  1088. bool check_column_name(const char *name)
  1089. {
  1090.   while (*name)
  1091.   {
  1092. #if defined(USE_MB) && defined(USE_MB_IDENT)
  1093.     if (use_mb(default_charset_info))
  1094.     {
  1095.       int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
  1096.       if (len)
  1097.       {
  1098.         name += len;
  1099.         continue;
  1100.       }
  1101.     }
  1102. #endif
  1103.     if (*name == NAMES_SEP_CHAR)
  1104.       return 1;
  1105.     name++;
  1106.   }
  1107.   return 0;
  1108. }
  1109.  
  1110. /*
  1111. ** Get type of table from .frm file
  1112. */
  1113.  
  1114. db_type get_table_type(const char *name)
  1115. {
  1116.   File     file;
  1117.   uchar head[4];
  1118.   int error;
  1119.   DBUG_ENTER("get_table_type");
  1120.   DBUG_PRINT("enter",("name: '%s'",name));
  1121.  
  1122.   if ((file=my_open(name,O_RDONLY, MYF(0))) < 0)
  1123.     DBUG_RETURN(DB_TYPE_UNKNOWN);
  1124.   error=my_read(file,(byte*) head,4,MYF(MY_NABP));
  1125.   my_close(file,MYF(0));
  1126.   if (error || head[0] != (uchar) 254 || head[1] != 1 ||
  1127.       (head[2] != FRM_VER && head[2] != FRM_VER+1))
  1128.     DBUG_RETURN(DB_TYPE_UNKNOWN);
  1129.   DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
  1130. }
  1131.  
  1132.  
  1133. /*****************************************************************************
  1134. ** Instansiate templates
  1135. *****************************************************************************/
  1136.  
  1137. #ifdef __GNUC__
  1138. template class List<String>;
  1139. template class List_iterator<String>;
  1140. #endif
  1141.