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 / handler.cpp < prev    next >
C/C++ Source or Header  |  2000-11-21  |  16KB  |  683 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. /* Handler-calling-functions */
  19.  
  20. #ifdef __GNUC__
  21. #pragma implementation                // gcc: Class implementation
  22. #endif
  23.  
  24. #include "mysql_priv.h"
  25. #include "ha_heap.h"
  26. #include "ha_myisam.h"
  27. #include "ha_myisammrg.h"
  28. #ifndef NO_ISAM
  29. #include "ha_isam.h"
  30. #include "ha_isammrg.h"
  31. #endif
  32. #ifdef HAVE_BERKELEY_DB
  33. #include "ha_berkeley.h"
  34. #endif
  35. #ifdef HAVE_INNOBASE_DB
  36. #include "ha_innobase.h"
  37. #endif
  38. #include <myisampack.h>
  39. #include <errno.h>
  40.  
  41.     /* static functions defined in this file */
  42.  
  43. static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
  44.  
  45. ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count,
  46.       ha_read_key_count, ha_read_next_count, ha_read_prev_count,
  47.       ha_read_first_count, ha_read_last_count,
  48.       ha_read_rnd_count, ha_read_rnd_next_count;
  49.  
  50. const char *ha_table_type[] = {
  51.   "", "DIAB_ISAM","HASH","MISAM","PISAM","RMS_ISAM","HEAP", "ISAM",
  52.   "MRG_ISAM","MYISAM", "MRG_MYISAM", "BDB", "INNOBASE", "?", "?",NullS
  53. };
  54.  
  55. const char *ha_row_type[] = {
  56.   "", "FIXED", "DYNAMIC", "COMPRESSED","?","?","?"
  57. };
  58.  
  59. TYPELIB ha_table_typelib= {array_elements(ha_table_type)-4,"",
  60.                ha_table_type+1};
  61.  
  62.  
  63.     /* Use other database handler if databasehandler is not incompiled */
  64.  
  65. enum db_type ha_checktype(enum db_type database_type)
  66. {
  67.   switch (database_type) {
  68. #ifdef HAVE_BERKELEY_DB
  69.   case DB_TYPE_BERKELEY_DB:
  70.     return(berkeley_skip ? DB_TYPE_MYISAM : database_type);
  71. #endif
  72. #ifdef HAVE_INNOBASE_DB
  73.   case DB_TYPE_INNOBASE:
  74.     return(innobase_skip ? DB_TYPE_MYISAM : database_type);
  75. #endif
  76. #ifndef NO_HASH
  77.   case DB_TYPE_HASH:
  78. #endif
  79. #ifndef NO_MERGE
  80.   case DB_TYPE_MRG_ISAM:
  81. #endif
  82. #ifndef NO_ISAM
  83.   case DB_TYPE_ISAM:
  84. #endif
  85.   case DB_TYPE_HEAP:
  86.   case DB_TYPE_MYISAM:
  87.   case DB_TYPE_MRG_MYISAM:
  88.     return (database_type);            /* Database exists on system */
  89.   default:
  90.     break;
  91.   }
  92.   return(DB_TYPE_MYISAM);            /* Use this as default */
  93. } /* ha_checktype */
  94.  
  95.  
  96. handler *get_new_handler(TABLE *table, enum db_type db_type)
  97. {
  98.   switch (db_type) {
  99. #ifndef NO_HASH
  100.   return new ha_hash(table);
  101. #endif
  102. #ifndef NO_MERGE
  103.   case DB_TYPE_MRG_ISAM:
  104.     return new ha_isammrg(table);
  105. #endif
  106. #ifndef NO_ISAM
  107.   case DB_TYPE_ISAM:
  108.     return new ha_isam(table);
  109. #endif
  110. #ifdef HAVE_BERKELEY_DB
  111.   case DB_TYPE_BERKELEY_DB:
  112.     return new ha_berkeley(table);
  113. #endif
  114. #ifdef HAVE_INNOBASE_DB
  115.   case DB_TYPE_INNOBASE_DB:
  116.     return new ha_innobase(table);
  117. #endif
  118.   case DB_TYPE_HEAP:
  119.     return new ha_heap(table);
  120.   case DB_TYPE_MYISAM:
  121.   default:                    // should never happen
  122.     return new ha_myisam(table);
  123.   case DB_TYPE_MRG_MYISAM:
  124.     return new ha_myisammrg(table);
  125.   }
  126. }
  127.  
  128. int ha_init()
  129. {
  130. #ifdef HAVE_BERKELEY_DB
  131.   if (!berkeley_skip)
  132.   {
  133.     int error;
  134.     if ((error=berkeley_init()))
  135.       return error;
  136.   }
  137. #endif
  138. #ifdef HAVE_INNOBASE_DB
  139.   if (!innobase_skip)
  140.   {
  141.     int error;
  142.     if ((error=innobase_init()))
  143.       return error;
  144.   }
  145. #endif
  146.   return 0;
  147. }
  148.  
  149.     /* close, flush or restart databases */
  150.     /* Ignore this for other databases than ours */
  151.  
  152. int ha_panic(enum ha_panic_function flag)
  153. {
  154.   int error=0;
  155. #ifndef NO_MERGE
  156.   error|=mrg_panic(flag);
  157. #endif
  158. #ifndef NO_HASH
  159.   error|=h_panic(flag);            /* fix hash */
  160. #endif
  161.   error|=heap_panic(flag);
  162.   error|=nisam_panic(flag);
  163.   error|=mi_panic(flag);
  164.   error|=myrg_panic(flag);
  165. #ifdef HAVE_BERKELEY_DB
  166.   if (!berkeley_skip)
  167.     error|=berkeley_end();
  168. #endif
  169. #ifdef HAVE_INNOBASE_DB
  170.   if (!innobase_skip)
  171.     error|=innobase_end();
  172. #endif
  173.   return error;
  174. } /* ha_panic */
  175.  
  176.  
  177. int ha_autocommit_or_rollback(THD *thd, int error)
  178. {
  179.   DBUG_ENTER("ha_autocommit_or_rollback");
  180. #if defined(HAVE_BERKELEY_DB) || defined(HAVE_INNOBASE_DB)
  181.   if ((thd->options & OPTION_AUTO_COMMIT) && !(thd->options & OPTION_BEGIN)
  182.       && !thd->locked_tables)
  183.   {
  184.     if (!error)
  185.     {
  186.       if (ha_commit(thd))
  187.     error=1;
  188.     }    
  189.     else
  190.       (void) ha_rollback(thd);
  191.   }
  192. #endif
  193.   DBUG_RETURN(error);
  194. }
  195.  
  196. int ha_commit(THD *thd)
  197. {
  198.   int error=0;
  199.   DBUG_ENTER("ha_commit");
  200. #ifdef HAVE_BERKELEY_DB
  201.   if (thd->transaction.bdb_tid)
  202.   {
  203.     int error=berkeley_commit(thd);
  204.     if (error)
  205.     {
  206.       my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
  207.       error=1;
  208.     }
  209.   }
  210. #endif
  211. #ifdef HAVE_INNOBASE_DB
  212.   if (thd->transaction.innobase_tid)
  213.   {
  214.     int error=innobase_commit(thd);
  215.     if (error)
  216.     {
  217.       my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
  218.       error=1;
  219.     }
  220.   }
  221. #endif
  222.   DBUG_RETURN(error);
  223. }
  224.  
  225. int ha_rollback(THD *thd)
  226. {
  227.   int error=0;
  228.   DBUG_ENTER("ha_rollback");
  229. #ifdef HAVE_BERKELEY_DB
  230.   if (thd->transaction.bdb_tid)
  231.   {
  232.     int error=berkeley_rollback(thd);
  233.     if (error)
  234.     {
  235.       my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
  236.       error=1;
  237.     }
  238.   }
  239. #endif
  240. #ifdef HAVE_INNOBASE_DB
  241.   if (thd->transaction.innobase_tid)
  242.   {
  243.     int error=innobase_rollback(thd);
  244.     if (error)
  245.     {
  246.       my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
  247.       error=1;
  248.     }
  249.   }
  250. #endif
  251.   DBUG_RETURN(error);
  252. }
  253.  
  254.  
  255. bool ha_flush_logs()
  256. {
  257.   bool result=0;
  258. #ifdef HAVE_BERKELEY_DB
  259.   if (!berkeley_skip && berkeley_flush_logs())
  260.     result=1;
  261. #endif
  262. #ifdef HAVE_INNOBASE_DB
  263.   if (!innobase_skip && innobase_flush_logs())
  264.     result=1;
  265. #endif
  266.   return result;
  267. }
  268.  
  269.  
  270. int ha_delete_table(enum db_type table_type, const char *path)
  271. {
  272.   handler *file=get_new_handler((TABLE*) 0, table_type);
  273.   if (!file)
  274.     return -1;
  275.   int error=file->delete_table(path);
  276.   delete file;
  277.   return error;
  278. }
  279.     
  280. void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos)
  281. {
  282.   switch (pack_length) {
  283. #if SIZEOF_OFF_T > 4
  284.   case 8: mi_int8store(buff,pos); break;
  285.   case 7: mi_int7store(buff,pos); break;
  286.   case 6: mi_int6store(buff,pos); break;
  287.   case 5: mi_int5store(buff,pos); break;
  288. #endif
  289.   case 4: mi_int4store(buff,pos); break;
  290.   case 3: mi_int3store(buff,pos); break;
  291.   case 2: mi_int2store(buff,(uint) pos); break;
  292.   case 1: buff[0]= (uchar) pos; break;
  293.   }
  294.   return;
  295. }
  296.  
  297. my_off_t ha_get_ptr(byte *ptr, uint pack_length)
  298. {
  299.   my_off_t pos;
  300.   switch (pack_length) {
  301. #if SIZEOF_OFF_T > 4
  302.   case 8:
  303.     pos= (my_off_t) mi_uint8korr(ptr);
  304.     break;
  305.   case 7:
  306.     pos= (my_off_t) mi_uint7korr(ptr);
  307.     break;
  308.   case 6:
  309.     pos= (my_off_t) mi_uint6korr(ptr);
  310.     break;
  311.   case 5:
  312.     pos= (my_off_t) mi_uint5korr(ptr);
  313.     break;
  314. #endif
  315.   case 4:
  316.     pos= (my_off_t) mi_uint4korr(ptr);
  317.     break;
  318.   case 3:
  319.     pos= (my_off_t) mi_uint3korr(ptr);
  320.     break;
  321.   case 2:
  322.     pos= (my_off_t) mi_uint2korr(ptr);
  323.     break;
  324.   case 1:
  325.     pos= (my_off_t) mi_uint2korr(ptr);
  326.     break;
  327.   default:
  328.     pos=0;                    // Impossible
  329.     break;
  330.   }
  331.  return pos;
  332. }
  333.  
  334. /****************************************************************************
  335. ** General handler functions
  336. ****************************************************************************/
  337.  
  338.     /* Open database-handler. Try O_RDONLY if can't open as O_RDWR */
  339.     /* Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set */
  340.  
  341. int handler::ha_open(const char *name, int mode, int test_if_locked)
  342. {
  343.   int error;
  344.   DBUG_ENTER("handler::open");
  345.   DBUG_PRINT("enter",("db_type: %d  db_stat: %d  mode: %d  lock_test: %d",
  346.               table->db_type, table->db_stat, mode, test_if_locked));
  347.  
  348.   if ((error=open(name,mode,test_if_locked)))
  349.   {
  350.     if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
  351.     (table->db_stat & HA_TRY_READ_ONLY))
  352.     {
  353.       table->db_stat|=HA_READ_ONLY;
  354.       error=open(name,O_RDONLY,test_if_locked);
  355.     }
  356.   }
  357.   if (error)
  358.   {
  359.     my_errno=error;            /* Safeguard */
  360.     DBUG_PRINT("error",("error: %d  errno: %d",error,errno));
  361.   }
  362.   else
  363.   {
  364.     if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
  365.       table->db_stat|=HA_READ_ONLY;
  366.   }
  367.   if (!error)
  368.   {
  369.     if (!alloc_root_inited(&table->mem_root))    // If temporary table
  370.       ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2);
  371.     else
  372.       ref=(byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2);
  373.     if (!ref)
  374.     {
  375.       close();
  376.       error=HA_ERR_OUT_OF_MEM;
  377.     }
  378.     else
  379.       dupp_ref=ref+ALIGN_SIZE(ref_length);
  380.   }
  381.   DBUG_RETURN(error);
  382. }
  383.  
  384. int handler::check(THD* thd, HA_CHECK_OPT* check_opt)
  385. {
  386.   return HA_ADMIN_NOT_IMPLEMENTED;
  387. }
  388.  
  389. int handler::backup(THD* thd, HA_CHECK_OPT* check_opt)
  390. {
  391.   return HA_ADMIN_NOT_IMPLEMENTED;
  392. }
  393.  
  394. int handler::restore(THD* thd, HA_CHECK_OPT* check_opt)
  395. {
  396.   return HA_ADMIN_NOT_IMPLEMENTED;
  397. }
  398.  
  399. int handler::repair(THD* thd, HA_CHECK_OPT* check_opt)
  400. {
  401.   return HA_ADMIN_NOT_IMPLEMENTED;
  402. }
  403.  
  404. int handler::optimize(THD* thd, HA_CHECK_OPT* check_opt)
  405. {
  406.   return HA_ADMIN_NOT_IMPLEMENTED;
  407. }
  408.  
  409. int handler::analyze(THD* thd, HA_CHECK_OPT* check_opt)
  410. {
  411.   return HA_ADMIN_NOT_IMPLEMENTED;
  412. }
  413.  
  414.     /* Read first row from a table */
  415.  
  416. int handler::rnd_first(byte * buf)
  417. {
  418.   register int error;
  419.   DBUG_ENTER("handler::rnd_first");
  420.  
  421.   statistic_increment(ha_read_first_count,&LOCK_status);
  422.   (void) rnd_init();
  423.   while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
  424.   (void) rnd_end();
  425.   DBUG_RETURN(error);
  426. }
  427.  
  428.  
  429. /*
  430.   The following function is only needed for tables that may be temporary tables
  431.   during joins
  432. */
  433.  
  434. int handler::restart_rnd_next(byte *buf, byte *pos)
  435. {
  436.   return HA_ERR_WRONG_COMMAND;
  437. }
  438.  
  439.  
  440.     /* Set a timestamp in record */
  441.  
  442. void handler::update_timestamp(byte *record)
  443. {
  444.   long skr= (long) current_thd->query_start();
  445. #ifdef WORDS_BIGENDIAN
  446.   if (table->db_low_byte_first)
  447.   {
  448.     int4store(record,skr);
  449.   }
  450.   else
  451. #endif
  452.   longstore(record,skr);
  453.   return;
  454. }
  455.  
  456.     /* Updates field with field_type NEXT_NUMBER according to following:
  457.     ** if field = 0 change field to the next free key in database.
  458.     */
  459.  
  460. void handler::update_auto_increment()
  461. {
  462.   longlong nr;
  463.   THD *thd;
  464.   DBUG_ENTER("update_auto_increment");
  465.   if (table->next_number_field->val_int() != 0)
  466.     DBUG_VOID_RETURN;
  467.   thd=current_thd;
  468.   if ((nr=thd->next_insert_id))
  469.     thd->next_insert_id=0;            // Clear after use
  470.   else
  471.     nr=get_auto_increment();
  472.   thd->insert_id((ulonglong) nr);
  473.   table->next_number_field->store(nr);
  474.   DBUG_VOID_RETURN;
  475. }
  476.  
  477.  
  478. longlong handler::get_auto_increment()
  479. {
  480.   longlong nr;
  481.   int error;
  482.   (void) extra(HA_EXTRA_KEYREAD);
  483.   index_init(table->next_number_index);
  484.   error=index_last(table->record[1]);
  485.   if (error)
  486.     nr=1;
  487.   else
  488.     nr=(longlong) table->next_number_field->
  489.       val_int_offset(table->rec_buff_length)+1;
  490.   (void) extra(HA_EXTRA_NO_KEYREAD);
  491.   index_end();
  492.   return nr;
  493. }
  494.  
  495.     /* Print error that we got from handler function */
  496.  
  497. void handler::print_error(int error, myf errflag)
  498. {
  499.   DBUG_ENTER("print_error");
  500.   DBUG_PRINT("enter",("error: %d",error));
  501.  
  502.   int textno=ER_GET_ERRNO;
  503.   switch (error) {
  504.   case EAGAIN:
  505.     textno=ER_FILE_USED;
  506.     break;
  507.   case ENOENT:
  508.     textno=ER_FILE_NOT_FOUND;
  509.     break;
  510.   case HA_ERR_KEY_NOT_FOUND:
  511.   case HA_ERR_NO_ACTIVE_RECORD:
  512.   case HA_ERR_END_OF_FILE:
  513.     textno=ER_KEY_NOT_FOUND;
  514.     break;
  515.   case HA_ERR_WRONG_TABLE_DEF:
  516.     textno=ER_WRONG_MRG_TABLE;
  517.     break;
  518.   case HA_ERR_FOUND_DUPP_KEY:
  519.   {
  520.     uint key_nr=get_dup_key(error);
  521.     if ((int) key_nr >= 0)
  522.     {
  523.       /* Write the dupplicated key in the error message */
  524.       char key[MAX_KEY_LENGTH];
  525.       String str(key,sizeof(key));
  526.       key_unpack(&str,table,(uint) key_nr);
  527.       uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_DUP_ENTRY));
  528.       if (str.length() >= max_length)
  529.       {
  530.     str.length(max_length-4);
  531.     str.append("...");
  532.       }
  533.       my_error(ER_DUP_ENTRY,MYF(0),str.c_ptr(),key_nr+1);
  534.       DBUG_VOID_RETURN;
  535.     }
  536.     textno=ER_DUP_KEY;
  537.     break;
  538.   }
  539.   case HA_ERR_FOUND_DUPP_UNIQUE:
  540.     textno=ER_DUP_UNIQUE;
  541.     break;
  542.   case HA_ERR_RECORD_CHANGED:
  543.     textno=ER_CHECKREAD;
  544.     break;
  545.   case HA_ERR_CRASHED:
  546.     textno=ER_NOT_KEYFILE;
  547.     break;
  548.   case HA_ERR_CRASHED_ON_USAGE:
  549.     textno=ER_CRASHED_ON_USAGE;
  550.     break;
  551.   case HA_ERR_CRASHED_ON_REPAIR:
  552.     textno=ER_CRASHED_ON_REPAIR;
  553.     break;
  554.   case HA_ERR_OUT_OF_MEM:
  555.     my_error(ER_OUT_OF_RESOURCES,errflag);
  556.     DBUG_VOID_RETURN;
  557.   case HA_ERR_WRONG_COMMAND:
  558.     textno=ER_ILLEGAL_HA;
  559.     break;
  560.   case HA_ERR_OLD_FILE:
  561.     textno=ER_OLD_KEYFILE;
  562.     break;
  563.   case HA_ERR_UNSUPPORTED:
  564.     textno=ER_UNSUPPORTED_EXTENSION;
  565.     break;
  566.   case HA_ERR_RECORD_FILE_FULL:
  567.     textno=ER_RECORD_FILE_FULL;
  568.     break;
  569.   default:
  570.     {
  571.       my_error(ER_GET_ERRNO,errflag,error);
  572.       DBUG_VOID_RETURN;
  573.     }
  574.   }
  575.   my_error(textno,errflag,table->table_name,error);
  576.   DBUG_VOID_RETURN;
  577. }
  578.  
  579.     /* Return key if error because of duplicated keys */
  580.  
  581. uint handler::get_dup_key(int error)
  582. {
  583.   DBUG_ENTER("key_error");
  584.   table->file->errkey  = (uint) -1;
  585.   if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE)
  586.     info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
  587.   DBUG_RETURN(table->file->errkey);
  588. }
  589.  
  590. int handler::delete_table(const char *name)
  591. {
  592.   for (const char **ext=bas_ext(); *ext ; ext++)
  593.   {
  594.     if (delete_file(name,*ext,2))
  595.       return my_errno;
  596.   }
  597.   return 0;
  598. }
  599.  
  600.  
  601. int handler::rename_table(const char * from, const char * to)
  602. {
  603.   DBUG_ENTER("handler::rename_table");
  604.   for (const char **ext=bas_ext(); *ext ; ext++)
  605.   {
  606.     if (rename_file_ext(from,to,*ext))
  607.       DBUG_RETURN(my_errno);
  608.   }
  609.   DBUG_RETURN(0);
  610. }
  611.  
  612.  
  613. int handler::index_next_same(byte *buf, const byte *key, uint keylen)
  614. {
  615.   int error;
  616.   if (!(error=index_next(buf)))
  617.   {
  618.     if (key_cmp(table, key, active_index, keylen))
  619.     {
  620.       table->status=STATUS_NOT_FOUND;
  621.       error=HA_ERR_END_OF_FILE;
  622.     }
  623.   }
  624.   return error;
  625. }
  626.  
  627.  
  628. /*
  629.   The following is only needed if we would like to use the database
  630.   for internal temporary tables
  631. */
  632.  
  633. int handler::delete_all_rows()
  634. {
  635.   return (my_errno=HA_ERR_WRONG_COMMAND);
  636. }
  637.  
  638. /****************************************************************************
  639. ** Some general functions that isn't in the handler class
  640. ****************************************************************************/
  641.  
  642.     /* Initiates table-file and calls apropriate database-creator */
  643.     /* Returns 1 if something got wrong */
  644.  
  645. int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
  646.             bool update_create_info)
  647.  
  648. {
  649.   int error;
  650.   TABLE table;
  651.   DBUG_ENTER("ha_create_table");
  652.  
  653.   if (openfrm(name,"",0,(uint) READ_ALL, 0, &table))
  654.     DBUG_RETURN(1);
  655.   if (update_create_info)
  656.   {
  657.     update_create_info_from_table(create_info, &table);
  658.     if (table.file->option_flag() & HA_DROP_BEFORE_CREATE)
  659.       table.file->delete_table(name);        // Needed for BDB tables
  660.   }
  661.   error=table.file->create(name,&table,create_info);
  662.   VOID(closefrm(&table));
  663.   if (error)
  664.     my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno);
  665.   DBUG_RETURN(error != 0);
  666. }
  667.  
  668.     /* Use key cacheing on all databases */
  669.  
  670. void ha_key_cache(void)
  671. {
  672.   if (keybuff_size)
  673.     (void) init_key_cache(keybuff_size,0);
  674. } /* ha_key_cache */
  675.  
  676.  
  677. static int NEAR_F delete_file(const char *name,const char *ext,int extflag)
  678. {
  679.   char buff[FN_REFLEN];
  680.   VOID(fn_format(buff,name,"",ext,extflag | 4));
  681.   return(my_delete(buff,MYF(MY_WME)));
  682. }
  683.