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 / dfunc.cpp < prev    next >
C/C++ Source or Header  |  1999-08-31  |  26KB  |  900 lines

  1. /* Copyright (C) 1979-1996 TcX AB & Monty Program KB & Detron HB
  2.  
  3.    This software is distributed with NO WARRANTY OF ANY KIND.  No author or
  4.    distributor accepts any responsibility for the consequences of using it, or
  5.    for whether it serves any particular purpose or works at all, unless he or
  6.    she says so in writing.  Refer to the Free Public License (the "License")
  7.    for full details.
  8.    Every copy of this file must include a copy of the License, normally in a
  9.    plain ASCII text file named PUBLIC.    The License grants you the right to
  10.    copy, modify and redistribute this file, but only under certain conditions
  11.    described in the License.  Among other things, the License requires that
  12.    the copyright notice and this notice be preserved on all copies. */
  13.  
  14. /* Diverse funktioner som anv{nds allt som oftast i datanet */
  15.  
  16. #include "mysql_priv.h"
  17. #include <errno.h>
  18.  
  19.  
  20.     /* Functions defined in this file */
  21.  
  22. static void frm_error(int error,TABLE *form,const char *name,int errortype);
  23. static void fix_type_pointers(my_string **array, TYPELIB *point_to_type,
  24.                   uint types, my_string *names);
  25. static uint find_field(TABLE *form,uint start,uint length);
  26.  
  27.  
  28. static byte* get_field_name(Field *buff,uint *length,my_bool not_used)
  29. {
  30.   *length= strlen(buff->field_name);
  31.   return (byte*) buff->field_name;
  32. }
  33.  
  34.     /* Open a .frm file */
  35.  
  36. int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
  37.         TABLE *outparam)
  38. {
  39.   reg1 uint i;
  40.   reg2 uchar *strpos;
  41.   int     j,flag,funktpos,error;
  42.   uint     rec_buff_length,n_length,int_length,records,key_parts,keys,
  43.     interval_count,interval_parts,read_length;
  44.   ulong  pos;
  45.   char     index_file[FN_REFLEN],*names;
  46.   uchar  head[288],*disk_buff,new_field_pack_flag;
  47.   my_string record,keynames,*int_array;
  48.   bool     new_frm_ver,use_hash,null_field_first;
  49.   File     file;
  50.   Field  **field,*reg_field;
  51.   KEY     *keyinfo;
  52.   KEY_PART_INFO *key_part;
  53.   uchar *null_pos;
  54.   uint null_bit;
  55.   SQL_CRYPT *crypted=0;
  56.   DBUG_ENTER("openfrm");
  57.   DBUG_PRINT("enter",("name: '%s'  form: %lx",name,outparam));
  58.  
  59.   bzero((char*) outparam,sizeof(*outparam));
  60.   disk_buff=NULL; record= NULL; keynames=NullS;
  61.   outparam->db_stat = db_stat;
  62.   funktpos=0; key_parts=0;
  63.   error=1;
  64.  
  65.   init_sql_alloc(&outparam->mem_root,1024);
  66.   MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
  67.   my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
  68.  
  69.   outparam->real_name=strdup_root(&outparam->mem_root,
  70.                   name+dirname_length(name));
  71.   *fn_ext(outparam->real_name)='\0';        // Remove extension
  72.   outparam->table_name=my_strdup(alias,MYF(MY_WME));
  73.   if (!outparam->real_name || !outparam->table_name)
  74.     goto err_end;
  75.  
  76.   flag= (prgflag & CHANGE_FRM) ? O_RDWR : O_RDONLY | O_SHARE;
  77.   if ((file=my_open(fn_format(index_file,name,"",reg_ext,4),flag,
  78.             MYF(0)))
  79.       < 0)
  80.   {
  81.     goto err_end; /* purecov: inspected */
  82.   }
  83.   error=4;
  84.   if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err;
  85.   if (head[0] != (uchar) 254 || head[1] != 1 ||
  86.       (head[2] != FRM_VER && head[2] != FRM_VER+1))
  87.     goto err; /* purecov: inspected */
  88.   new_field_pack_flag=head[27];
  89.   new_frm_ver= (head[2] == FRM_VER+1);
  90.  
  91.   error=3;
  92.   if (!(pos=get_form_pos(file,head,NullS,(TYPELIB*) 0)))
  93.     goto err; /* purecov: inspected */
  94.   *fn_ext(index_file)='\0';            // Remove .frm extension
  95.  
  96.   outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
  97.   outparam->db_create_options=uint2korr(head+30);
  98.   outparam->db_record_offset=1;
  99.   null_field_first=0;
  100.   if (!head[32])                // New frm file in 3.23
  101.   {
  102.     null_field_first=1;
  103.   }
  104.  
  105.   error=4;
  106.   outparam->max_records=uint4korr(head+18);
  107.   outparam->reloc=uint4korr(head+22);
  108.  
  109.   /* Read keyinformation */
  110.   VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
  111.   if (read_string(file,(gptr*) &disk_buff,(uint) uint2korr(head+28)))
  112.     goto err; /* purecov: inspected */
  113.   outparam->keys=keys=disk_buff[0];
  114.   key_parts=disk_buff[1];
  115.   n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
  116.   if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root,
  117.                     n_length+uint2korr(disk_buff+4))))
  118.     goto err; /* purecov: inspected */
  119.   bzero((char*) keyinfo,n_length);
  120.   outparam->key_info=keyinfo;
  121.   outparam->max_key_length=0;
  122.   /* key_part= (KEY_PART_INFO*) (keyinfo+keys); */
  123.   key_part= my_reinterpret_cast(KEY_PART_INFO*) (keyinfo+keys);
  124.   strpos=disk_buff+6;
  125.   for (i=0 ; i < keys ; i++, keyinfo++)
  126.   {
  127.     keyinfo->dupp_key=     (uint) strpos[0];
  128.     keyinfo->key_length= (uint) uint2korr(strpos+1);
  129.     keyinfo->key_parts=  (uint) strpos[3];  strpos+=4;
  130.     keyinfo->key_part=     key_part;
  131.     set_if_bigger(outparam->max_key_length,keyinfo->key_length);
  132.     for (j=keyinfo->key_parts ; j-- ; key_part++)
  133.     {
  134.       key_part->fieldnr=    (uint16) (uint2korr(strpos) & FIELD_NR_MASK);
  135.       key_part->offset= (uint) uint2korr(strpos+2)-1;
  136.       key_part->key_type=    (uint) uint2korr(strpos+5);
  137.       key_part->field=    (Field*) 0;    // Will be fixed later
  138.       if (new_frm_ver)
  139.       {
  140.     key_part->key_part_flag=    *(strpos+4);
  141.     key_part->length=    (uint) uint2korr(strpos+7);
  142.     strpos+=9;
  143.       }
  144.       else
  145.       {
  146.     key_part->length=    *(strpos+4);
  147.     key_part->key_part_flag=0;
  148.     if (key_part->length > 128)
  149.     {
  150.       key_part->length&=127; /* purecov: inspected */
  151.       key_part->key_part_flag=HA_REVERSE_SORT; /* purecov: inspected */
  152.     }
  153.     strpos+=7;
  154.       }
  155.     }
  156.   }
  157.   VOID(strmov(keynames= (my_string) key_part,(my_string) strpos));
  158.   outparam->reclength = uint2korr((head+16));
  159.   if (*(head+26)  == 1)
  160.     outparam->system=1;                /* one-record-database */
  161. #ifdef HAVE_CRYPTED_FRM
  162.   else if (*(head+26) == 2)
  163.   {
  164.     extern SQL_CRYPT *get_crypt_for_frm(void);
  165.     my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  166.     crypted=get_crypt_for_frm();
  167.     my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
  168.     outparam->crypted=1;
  169.   }
  170. #endif
  171.  
  172.   error=2;
  173.   if ((ha_open(outparam,index_file,
  174.            (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
  175.            (db_stat & HA_WAIT_IF_LOCKED ||
  176.         specialflag & SPECIAL_WAIT_IF_LOCKED ?
  177.         HA_OPEN_WAIT_IF_LOCKED :
  178.         (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
  179.         HA_OPEN_ABORT_IF_LOCKED : HA_OPEN_IGNORE_IF_LOCKED))))
  180.     goto err; /* purecov: inspected */
  181.   error=4; funktpos=1;
  182.   outparam->reginfo.lock_type= TL_UNLOCK;
  183.   if (db_stat & HA_OPEN_KEYFILE || (prgflag & DELAYED_OPEN)) records=2;
  184.   else records=1;
  185.   if (prgflag & (READ_ALL+EXTRA_RECORD)) records++;
  186.   rec_buff_length=ALIGN_SIZE(outparam->reclength+1);
  187.   if (!(outparam->record[0]= (byte*)
  188.     (record = (char *) alloc_root(&outparam->mem_root,
  189.                       rec_buff_length * records))))
  190.     goto err;                    /* purecov: inspected */
  191.   record[outparam->reclength]=0;        // For purify and ->c_ptr()
  192.   outparam->rec_buff_length=rec_buff_length;
  193.   if (my_pread(file,(byte*) record,(uint) outparam->reclength,
  194.            (ulong) (uint2korr(head+6)+uint2korr(head+14)),
  195.            MYF(MY_NABP)))
  196.     goto err; /* purecov: inspected */
  197.   for (i=0 ; i < records ; i++, record+=rec_buff_length)
  198.   {
  199.     outparam->record[i]=(byte*) record;
  200.     if (i)
  201.       memcpy(record,record-rec_buff_length,(uint) outparam->reclength);
  202.   }
  203.  
  204.   if (records == 2)
  205.   {                        /* fix for select */
  206.     outparam->record[2]=outparam->record[1];
  207.     if (db_stat & HA_READ_ONLY)
  208.       outparam->record[1]=outparam->record[0]; /* purecov: inspected */
  209.   }
  210.  
  211.   VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
  212.   if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err;
  213.   if (crypted)
  214.   {
  215.     crypted->decode((char*) head+256,288-256);
  216.     if (sint2korr(head+284) != 0)        // Should be 0
  217.       goto err;                    // Wrong password
  218.   }
  219.  
  220.   outparam->fields= uint2korr(head+258);
  221.   pos=uint2korr(head+260);            /* Length of all screens */
  222.   n_length=uint2korr(head+268);
  223.   interval_count=uint2korr(head+270);
  224.   interval_parts=uint2korr(head+272);
  225.   int_length=uint2korr(head+274);
  226.   outparam->null_fields=uint2korr(head+282);
  227.  
  228.   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));
  229.  
  230.   if (!(field = (Field **)
  231.     alloc_root(&outparam->mem_root,
  232.                (uint) ((outparam->fields+1)*sizeof(Field*)+
  233.                    interval_count*sizeof(TYPELIB)+
  234.                    (outparam->fields+interval_parts+
  235.                 keys+3)*sizeof(my_string)+
  236.                    (n_length+int_length)))))
  237.     goto err; /* purecov: inspected */
  238.  
  239.   outparam->field=field;
  240.   read_length=((uint) (outparam->fields*11)+pos+
  241.            (uint) (n_length+int_length));
  242.   if (read_string(file,(gptr*) &disk_buff,read_length))
  243.     goto err; /* purecov: inspected */
  244.   if (crypted)
  245.   {
  246.     crypted->decode((char*) disk_buff,read_length);
  247.     delete crypted;
  248.     crypted=0;
  249.   }
  250.   strpos= disk_buff+pos;
  251.  
  252.   outparam->intervals= (TYPELIB*) (outparam->field+outparam->fields+1);
  253.   int_array= (my_string*) (outparam->intervals+interval_count);
  254.   names= (char*) (int_array+outparam->fields+interval_parts+keys+3);
  255.   if (!interval_count)
  256.     outparam->intervals=0;            // For better debugging
  257.   memcpy(names, strpos+(outparam->fields*11), (uint) (n_length+int_length));
  258.  
  259.   fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
  260.   fix_type_pointers(&int_array,outparam->intervals,interval_count,
  261.             &names);
  262.   if (keynames)
  263.     fix_type_pointers(&int_array,&outparam->keynames,1,&keynames);
  264.   VOID(my_close(file,MYF(MY_WME)));
  265.  
  266.   record=(char*) outparam->record[0]-1;        /* Fieldstart = 1 */
  267.   if (null_field_first)
  268.   {
  269.     outparam->null_flags=null_pos= (uchar*) record+1;
  270.     null_bit= (outparam->db_create_options & HA_OPTION_PACK_RECORD) ? 1 : 2;
  271.     outparam->null_bytes=(outparam->null_fields+null_bit+6)/8;
  272.   }
  273.   else
  274.   {
  275.     outparam->null_bytes=(outparam->null_fields+7)/8;
  276.     outparam->null_flags=null_pos=
  277.       (uchar*) (record+1+outparam->reclength-outparam->null_bytes);
  278.     null_bit=1;
  279.   }
  280.  
  281.   use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
  282.   if (use_hash)
  283.     use_hash= !hash_init(&outparam->name_hash,
  284.              outparam->fields,0,0,
  285.              (hash_get_key) get_field_name,0,
  286.              HASH_CASE_INSENSITIVE);
  287.  
  288.   for (i=0 ; i < outparam->fields; i++, strpos+= 11, field++)
  289.   {
  290.     uint pack_flag= uint2korr(strpos+6);
  291.     uint interval_nr= (uint) strpos[10];
  292.  
  293.     *field=reg_field=make_field(record+uint2korr(strpos+4),
  294.                 (uint32) strpos[3], // field_length
  295.                 null_pos,null_bit,
  296.                 pack_flag,
  297.                 (Field::utype) MTYP_TYPENR((uint) strpos[8]),
  298.                 (interval_nr ?
  299.                  outparam->intervals+interval_nr-1 :
  300.                  (TYPELIB*) 0),
  301.                 outparam->fieldnames.type_names[i],
  302.                 outparam);
  303.     if (!(reg_field->flags & NOT_NULL_FLAG))
  304.     {
  305.       if ((null_bit<<=1) == 256)
  306.       {
  307.     null_pos++;
  308.     null_bit=1;
  309.       }
  310.     }
  311.     if (reg_field->unireg_check == Field::NEXT_NUMBER)
  312.     {
  313.       if ((int) (outparam->next_number_index= (uint)
  314.          find_ref_key(outparam,reg_field)) < 0)
  315.     reg_field->unireg_check=Field::NONE;    /* purecov: inspected */
  316.       else
  317.       {
  318.     outparam->found_next_number_field=reg_field;
  319.     reg_field->flags|=AUTO_INCREMENT_FLAG;
  320.       }
  321.     }
  322.     if (use_hash)
  323.       (void) hash_insert(&outparam->name_hash,(byte*) *field); // Will never fail
  324.   }
  325.   outparam->key_parts=key_parts;
  326.   *field=0;                    // End marker
  327.  
  328.   /* Fix key->name and key_part->field */
  329.   if (key_parts)
  330.   {
  331.     uint primary_key=(uint) (find_type("PRIMARY",&outparam->keynames,3)-1);
  332.     uint ha_option=ha_option_flag[outparam->db_type];
  333.     keyinfo=outparam->key_info;
  334.     key_part=keyinfo->key_part;
  335.  
  336.     for (uint key=0 ; key < outparam->keys ; key++,keyinfo++)
  337.     {
  338.       uint usable_parts=0;
  339.       keyinfo->name=outparam->keynames.type_names[key];
  340.       if (primary_key >= MAX_KEY && !keyinfo->dupp_key)
  341.     primary_key=key;
  342.  
  343.       for (i=0 ; i < keyinfo->key_parts ; key_part++,i++)
  344.       {
  345.     if (new_field_pack_flag <= 1)
  346.       key_part->fieldnr=(uint16) find_field(outparam,
  347.                         (uint) key_part->offset,
  348.                         (uint) key_part->length);
  349.     if (key_part->fieldnr)
  350.     {                    // Should always be true !
  351.       key_part->field=outparam->field[key_part->fieldnr-1];
  352.       if (i == 0 && key != primary_key)
  353.         key_part->field->flags |=
  354.           (!keyinfo->dupp_key &&
  355.            key_part->field->pack_length() ==
  356.            keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
  357.       if (i == 0)
  358.         key_part->field->key_start|= ((key_map) 1 << key);
  359.       if (ha_option & HA_HAVE_KEYREAD_ONLY &&
  360.           key_part->field->pack_length() == key_part->length)
  361.  
  362.       {
  363.         if (key_part->field->key_type() != HA_KEYTYPE_TEXT ||
  364.         !(ha_option & HA_KEYREAD_WRONG_STR))
  365.           key_part->field->part_of_key|= ((key_map) 1 << key);
  366.       }
  367.       if (!key_part->key_part_flag && usable_parts == i)
  368.         usable_parts++;            // For FILESORT
  369.       key_part->field->flags|= PART_KEY_FLAG;
  370.       if (key == primary_key)
  371.         key_part->field->flags|= PRI_KEY_FLAG;
  372.  
  373.       if (key_part->field->pack_length() != key_part->length)
  374.       {                    // Create a new field
  375.         key_part->field=key_part->field->new_field(outparam);
  376.         key_part->field->field_length=key_part->length;
  377.       }
  378.     }
  379.     else
  380.     {                    // Error: shorten key
  381.       keyinfo->key_parts=usable_parts;
  382.       keyinfo->dupp_key=0;
  383.     }
  384.       }
  385.       keyinfo->usable_key_parts=usable_parts; // Filesort
  386.     }
  387.   }
  388.   x_free((gptr) disk_buff);
  389.   if (new_field_pack_flag <= 1)
  390.   {            /* Old file format with default null */
  391.     uint null_length=(outparam->null_fields+7)/8;
  392.     bfill(outparam->null_flags,null_length,255);
  393.     bfill(outparam->null_flags+outparam->rec_buff_length,null_length,255);
  394.     if (records > 2)
  395.       bfill(outparam->null_flags+outparam->rec_buff_length*2,null_length,255);
  396.   }
  397.   my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  398.   opened_tables++;
  399. #ifndef DBUG_OFF
  400.   if (use_hash)
  401.     (void) hash_check(&outparam->name_hash);
  402. #endif
  403.   DBUG_RETURN (0);
  404.  
  405.  err:
  406.   if (funktpos)
  407.   {
  408.     VOID(ha_close(outparam));
  409.     outparam->file=0;                // For easyer errorchecking
  410.     outparam->fields=0;                // Probably safe
  411.   }
  412.  
  413.   x_free((gptr) disk_buff);
  414.   delete crypted;
  415.   VOID(my_close(file,MYF(MY_WME)));
  416.  
  417.  err_end:                    /* Here when no file */
  418.   delete crypted;
  419.   my_pthread_setspecific_ptr(THR_MALLOC,old_root);
  420.   frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG);
  421.   free_root(&outparam->mem_root);
  422.   my_free(outparam->table_name,MYF(0));
  423.   DBUG_RETURN (error);
  424. } /* openfrm */
  425.  
  426.  
  427.     /* close a .frm file and it's tables*/
  428.  
  429. int closefrm(register TABLE *table)
  430. {
  431.   int error=0;
  432.   DBUG_ENTER("closefrm");
  433.   if (table->db_stat)
  434.     error=ha_close(table);
  435. #ifdef NOT_USED                    // For old DIAB ISAM
  436.   else if (table->dfile)
  437.     error=my_close(table->dfile,MYF(MY_WME)); /* purecov: deadcode */
  438. #endif
  439.   if (table->table_name)
  440.   {
  441.     my_free(table->table_name,MYF(0));
  442.     table->table_name=0;
  443.   }
  444.   if (table->fields)
  445.   {
  446.     for (Field **ptr=table->field ; *ptr ; ptr++)
  447.       delete *ptr;
  448.     table->fields=0;
  449.   }
  450.   free_root(&table->mem_root);
  451.   hash_free(&table->name_hash);
  452.   table->file=0;                /* For easyer errorchecking */
  453.   DBUG_RETURN(error);
  454. }
  455.  
  456.  
  457. /* Deallocte temporary blob storage */
  458.  
  459. void free_blobs(register TABLE *table)
  460. {
  461.   for (Field **ptr=table->field ; *ptr ; ptr++)
  462.   {
  463.     if ((*ptr)->flags & BLOB_FLAG)
  464.       ((Field_blob *) (*ptr))->free();
  465.   }
  466. }
  467.  
  468.  
  469.     /* Find where a form starts */
  470.     /* if formname is NullS then only formnames is read */
  471.  
  472. ulong get_form_pos(File file, uchar *head, my_string outname,
  473.            TYPELIB *save_names)
  474. {
  475.   uint a_length,names,length;
  476.   uchar *pos,*buf;
  477.   ulong ret_value=0;
  478.   DBUG_ENTER("get_form_pos");
  479.  
  480.   names=uint2korr(head+8);
  481.   a_length=(names+2)*sizeof(my_string);        /* Room for two extra */
  482.  
  483.   if (!save_names)
  484.     a_length=0;
  485.   else
  486.     save_names->type_names=0;            /* Clear if error */
  487.  
  488.   if (outname && head[32])
  489.     VOID(strmake((char*) outname,(char*) head+32,32));
  490.  
  491.   if (names)
  492.   {
  493.     length=uint2korr(head+4);
  494.     VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0)));
  495.     if (!(buf= (uchar*) my_malloc((uint) length+a_length+names*4,
  496.                   MYF(MY_WME))) ||
  497.     my_read(file,(byte*) buf+a_length,(uint) (length+names*4),
  498.         MYF(MY_NABP)))
  499.     {                        /* purecov: inspected */
  500.       x_free((gptr) buf);            /* purecov: inspected */
  501.       DBUG_RETURN(0L);                /* purecov: inspected */
  502.     }
  503.     pos= buf+a_length+length;
  504.     ret_value=uint4korr(pos);
  505.   }
  506.   if (! save_names)
  507.     my_free((gptr) buf,MYF(0));
  508.   else if (!names)
  509.     bzero((char*) save_names,sizeof(save_names));
  510.   else
  511.   {
  512.     char *str;
  513.     str=(my_string) (buf+a_length);
  514.     fix_type_pointers((my_string**) &buf,save_names,1,&str);
  515.   }
  516.   DBUG_RETURN(ret_value);
  517. }
  518.  
  519.  
  520.     /* Read string from a file with malloc */
  521.  
  522. int read_string(File file, gptr *to, uint length)
  523. {
  524.   DBUG_ENTER("read_string");
  525.  
  526.   x_free((gptr) *to);
  527.   if (!(*to= (gptr) my_malloc(length+1,MYF(MY_WME))) ||
  528.       my_read(file,(byte*) *to,length,MYF(MY_NABP)))
  529.   {
  530.     x_free((gptr) *to); /* purecov: inspected */
  531.     *to= 0; /* purecov: inspected */
  532.     DBUG_RETURN(1); /* purecov: inspected */
  533.   }
  534.   *((char*) *to+length)= '\0';
  535.   DBUG_RETURN (0);
  536. } /* read_string */
  537.  
  538.  
  539.     /* Add a new form to a form file */
  540.  
  541. ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames,
  542.              my_string newname)
  543. {
  544.   uint i,bufflength,maxlength,n_length,length,names;
  545.   ulong endpos,newpos;
  546.   char buff[IO_SIZE];
  547.   uchar *pos;
  548.   DBUG_ENTER("make_new_entry");
  549.  
  550.   length=strlen(newname)+1;
  551.   n_length=uint2korr(fileinfo+4);
  552.   maxlength=uint2korr(fileinfo+6);
  553.   names=uint2korr(fileinfo+8);
  554.   newpos=uint4korr(fileinfo+10);
  555.  
  556.   if (64+length+n_length+(names+1)*4 > maxlength)
  557.   {                        /* Expand file */
  558.     newpos+=IO_SIZE;
  559.     int4store(fileinfo+10,newpos);
  560.     endpos=my_seek(file,0L,MY_SEEK_END,MYF(0)); /* Copy from file-end */
  561.     bufflength= (uint) (endpos & (IO_SIZE-1));    /* IO_SIZE is a power of 2 */
  562.  
  563.     while (endpos > maxlength)
  564.     {
  565.       VOID(my_seek(file,(ulong) (endpos-bufflength),MY_SEEK_SET,MYF(0)));
  566.       if (my_read(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
  567.     DBUG_RETURN(0L);
  568.       VOID(my_seek(file,(ulong) (endpos-bufflength+IO_SIZE),MY_SEEK_SET,
  569.            MYF(0)));
  570.       if ((my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME))))
  571.     DBUG_RETURN(0);
  572.       endpos-=bufflength; bufflength=IO_SIZE;
  573.     }
  574.     bzero(buff,IO_SIZE);            /* Null new block */
  575.     VOID(my_seek(file,(ulong) maxlength,MY_SEEK_SET,MYF(0)));
  576.     if (my_write(file,(byte*) buff,bufflength,MYF(MY_NABP+MY_WME)))
  577.     DBUG_RETURN(0L);
  578.     maxlength+=IO_SIZE;                /* Fix old ref */
  579.     int2store(fileinfo+6,maxlength);
  580.     for (i=names, pos= (uchar*) *formnames->type_names+n_length-1; i-- ;
  581.      pos+=4)
  582.     {
  583.       endpos=uint4korr(pos)+IO_SIZE;
  584.       int4store(pos,endpos);
  585.     }
  586.   }
  587.  
  588.   if (n_length == 1 )
  589.   {                        /* First name */
  590.     length++;
  591.     VOID(strxmov(buff,"/",newname,"/",NullS));
  592.   }
  593.   else
  594.     VOID(strxmov(buff,newname,"/",NullS)); /* purecov: inspected */
  595.   VOID(my_seek(file,63L+(ulong) n_length,MY_SEEK_SET,MYF(0)));
  596.   if (my_write(file,(byte*) buff,(uint) length+1,MYF(MY_NABP+MY_WME)) ||
  597.       (names && my_write(file,(byte*) (*formnames->type_names+n_length-1),
  598.              names*4, MYF(MY_NABP+MY_WME))) ||
  599.       my_write(file,(byte*) fileinfo+10,(uint) 4,MYF(MY_NABP+MY_WME)))
  600.     DBUG_RETURN(0L); /* purecov: inspected */
  601.  
  602.   int2store(fileinfo+8,names+1);
  603.   int2store(fileinfo+4,n_length+length);
  604.   VOID(my_chsize(file,newpos,MYF(MY_WME)));    /* Append file with '\0' */
  605.   DBUG_RETURN(newpos);
  606. } /* make_new_entry */
  607.  
  608.  
  609.     /* error message when opening a form file */
  610.  
  611. static void frm_error(int error, TABLE *form, const char *name, myf errortype)
  612. {
  613.   int er_no;
  614.   char buff[FN_REFLEN],*form_dev="",*datext;
  615.   DBUG_ENTER("frm_error");
  616.  
  617.   switch (error) {
  618.   case 1:
  619.     if (my_errno == ENOENT)
  620.     {
  621.       char *db;
  622.       uint length=dirname_part(buff,name);
  623.       buff[length-1]=0;
  624.       db=buff+dirname_length(buff);
  625.       my_error(ER_NO_SUCH_TABLE,MYF(0),db,form->real_name);
  626.     }
  627.     else
  628.       my_error(ER_FILE_NOT_FOUND,errortype,
  629.            fn_format(buff,name,form_dev,reg_ext,0),my_errno);
  630.     break;
  631.   case 2:
  632.   {
  633.     datext=bas_ext[form->db_type][test(form->db_stat & HA_OPEN_KEYFILE)];
  634.     er_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
  635.       ER_FILE_USED : ER_CANT_OPEN_FILE;
  636.     my_error(er_no,errortype,
  637.          fn_format(buff,form->real_name,form_dev,datext,2),my_errno);
  638.     break;
  639.   }
  640.   default:                /* Better wrong error than none */
  641.   case 4:
  642.     my_error(ER_NOT_FORM_FILE,errortype,
  643.          fn_format(buff,name,form_dev,reg_ext,0));
  644.     break;
  645.   }
  646.   DBUG_VOID_RETURN;
  647. } /* frm_error */
  648.  
  649.  
  650.     /*
  651.     ** fix a str_type to a array type
  652.     ** typeparts sepearated with some char. differents types are separated
  653.     ** with a '\0'
  654.     */
  655.  
  656. static void
  657. fix_type_pointers(my_string **array, TYPELIB *point_to_type, uint types,
  658.           my_string *names)
  659. {
  660.   my_string type_name,ptr;
  661.   char chr;
  662.  
  663.   ptr= *names;
  664.   while (types--)
  665.   {
  666.     point_to_type->name=0;
  667.     point_to_type->type_names= *array;
  668.  
  669.     if ((chr= *ptr))            /* Test if empty type */
  670.     {
  671.       while ((type_name=strchr(ptr+1,chr)) != NullS)
  672.       {
  673.     *((*array)++) = ptr+1;
  674.     *type_name= '\0';        /* End string */
  675.     ptr=type_name;
  676.       }
  677.       ptr+=2;                /* Skipp end mark and last 0 */
  678.     }
  679.     else
  680.       ptr++;
  681.     point_to_type->count= (uint) (*array - point_to_type->type_names);
  682.     point_to_type++;
  683.     *((*array)++)= NullS;        /* End of type */
  684.   }
  685.   *names=ptr;                /* Update end */
  686.   return;
  687. } /* fix_type_pointers */
  688.  
  689.  
  690. TYPELIB *typelib(List<String> &strings)
  691. {
  692.   TYPELIB *result=(TYPELIB*) sql_alloc(sizeof(TYPELIB));
  693.   result->count=strings.elements;
  694.   result->name="";
  695.   result->type_names=(my_string*) sql_alloc(sizeof(my_string**)*(result->count+1));
  696.  
  697.   List_iterator<String> it(strings);
  698.   String *tmp;
  699.   for (uint i=0; (tmp=it++) ; i++)
  700.     result->type_names[i]=(char*) tmp->ptr();
  701.   result->type_names[result->count]=0;        // End marker
  702.   return result;
  703. }
  704.  
  705.  
  706.     /*
  707.     ** Search after a field with given start & length
  708.     ** If an exact field isn't found, return longest field with starts
  709.     ** at right position.
  710.     ** Return 0 on error, else field number+1
  711.     ** This is needed because in some .frm fields 'fieldnr' was saved wrong
  712.     */
  713.  
  714. static uint find_field(TABLE *form,uint start,uint length)
  715. {
  716.   Field **field;
  717.   uint i,pos;
  718.  
  719.   pos=0;
  720.  
  721.   for (field=form->field, i=1 ; i<= form->fields ; i++,field++)
  722.   {
  723.     if ((*field)->offset() == start)
  724.     {
  725.       if ((*field)->pack_length() == length)
  726.     return (i);
  727.       if (!pos || form->field[pos-1]->pack_length() <
  728.       (*field)->pack_length())
  729.     pos=i;
  730.     }
  731.   }
  732.   return (pos);
  733. }
  734.  
  735.  
  736.     /* Kontrollerar att integern passar inom gr{nserna */
  737.  
  738. int set_zone(register int nr, int min_zone, int max_zone)
  739. {
  740.   if (nr<=min_zone)
  741.     return (min_zone);
  742.   if (nr>=max_zone)
  743.     return (max_zone);
  744.   return (nr);
  745. } /* set_zone */
  746.  
  747.     /* Justerar ett tal till n{sta j{mna diskbuffer */
  748.  
  749. ulong next_io_size(register ulong pos)
  750. {
  751.   reg2 ulong offset;
  752.   if ((offset= pos & (IO_SIZE-1)))
  753.     return pos-offset+IO_SIZE;
  754.   return pos;
  755. } /* next_io_size */
  756.  
  757.  
  758. void append_unescaped(String *res,const char *pos)
  759. {
  760.   for ( ; *pos ; pos++)
  761.   {
  762.     switch (*pos) {
  763.     case 0:                /* Must be escaped for 'mysql' */
  764.       res->append('\\');
  765.       res->append('0');
  766.       break;
  767.     case '\n':                /* Must be escaped for logs */
  768.       res->append('\\');
  769.       res->append('n');
  770.       break;
  771.     case '\r':
  772.       res->append('\\');        /* This gives better readbility */
  773.       res->append('r');
  774.       break;
  775.     case '\\':
  776.       res->append('\\');        /* Because of the sql syntax */
  777.       res->append('\\');
  778.       break;
  779.     case '\'':
  780.       res->append('\'');        /* Because of the sql syntax */
  781.       res->append('\'');
  782.       break;
  783.     default:
  784.       res->append(*pos);
  785.       break;
  786.     }
  787.   }
  788. }
  789.  
  790.     /* Create a .frm file */
  791.  
  792. File create_frm(register my_string name, uint reclength, uchar *fileinfo,
  793.         enum db_type database, uint options, ha_rows records,
  794.         ha_rows reloc,uint keys)
  795. {
  796.   register File file;
  797.   uint key_length;
  798.   ulong length;
  799.   char fill[IO_SIZE];
  800.  
  801.   if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
  802.   {
  803.     bzero((char*) fileinfo,64);
  804.     fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+1; // Header
  805.     fileinfo[3]= (uchar) ha_checktype(database);
  806.     fileinfo[4]=1;
  807.     int2store(fileinfo+6,IO_SIZE);        /* Next block starts here */
  808.     key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16;
  809.     length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength));
  810.     int4store(fileinfo+10,length);
  811.     int2store(fileinfo+14,key_length);
  812.     int2store(fileinfo+16,reclength);
  813.     int4store(fileinfo+18,records);
  814.     int4store(fileinfo+22,reloc);
  815.     fileinfo[27]=2;                /* Use long pack-fields */
  816.     int2store(fileinfo+30,options);
  817.     VOID(fn_format((char*) fileinfo+32,name,"","",3));
  818.     bzero(fill,IO_SIZE);
  819.     for (; length > IO_SIZE ; length-= IO_SIZE)
  820.     {
  821.       if (my_write(file,(byte*) fill,IO_SIZE,MYF(MY_WME | MY_NABP)))
  822.       {
  823.     VOID(my_close(file,MYF(0)));
  824.     VOID(my_delete(name,MYF(0)));
  825.     return(-1);
  826.       }
  827.     }
  828.   }
  829.   return (file);
  830. } /* create_frm */
  831.  
  832.  
  833. int
  834. rename_file_ext(const char * from,const char * to,const char * ext)
  835. {
  836.   char from_b[FN_REFLEN],to_b[FN_REFLEN];
  837.   VOID(strxmov(from_b,from,ext,NullS));
  838.   VOID(strxmov(to_b,to,ext,NullS));
  839.   return (my_rename(from_b,to_b,MYF(MY_WME)));
  840. }
  841.  
  842.  
  843. /*
  844. ** Change the current ref in the .frm file to the current file name
  845. */
  846.  
  847. int fix_frm_ref(const char * name)
  848. {
  849.   char buff[FN_REFLEN];
  850.   int error= -1;
  851.   uint length;
  852.   File file;
  853.   DBUG_ENTER("fix_frm_ref");
  854.  
  855.   if ((file=my_open(fn_format(buff,name,"",reg_ext,2+4),O_RDWR,MYF_RW)) >= 0)
  856.   {
  857.     if (!(my_pread(file,(byte*) buff,32,32,MYF_RW | MY_WME)))
  858.     {
  859.       bzero(buff+32,32);                /* Remove old name */
  860.       length=dirname_length(name);
  861.       if (strlen(name)-length < 32)
  862.     strmov(buff,name+length);
  863.       if (!my_pwrite(file,(byte*) buff,32,32,MYF_RW | MY_WME))
  864.     error=0;
  865.     }
  866.     VOID(my_close(file,MYF(MY_WME)));
  867.   }
  868.   DBUG_RETURN(error);
  869. }
  870.  
  871. /*
  872.   Alloc a value as a string and return it
  873.   If field is empty, return NULL
  874. */
  875.  
  876. char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr)
  877. {
  878.   Field *field=table->field[fieldnr];
  879.   char buff[MAX_FIELD_WIDTH];
  880.   String str(buff,sizeof(buff));
  881.   field->val_str(&str,&str);
  882.   uint length=str.length();
  883.   if (!length)
  884.     return NullS;
  885.   char *to=alloc_root(mem,length+1);
  886.   memcpy(to,str.ptr(),(uint) length);
  887.   to[length]=0;
  888.   return to;
  889. }
  890.  
  891.  
  892. /*****************************************************************************
  893. ** Instansiate templates
  894. *****************************************************************************/
  895.  
  896. #ifdef __GNUC__
  897. template class List<String>;
  898. template class List_iterator<String>;
  899. #endif
  900.