log.cc
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:25k
源码类别:

MySQL数据库

开发平台:

Visual C++

  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. /* logging of commands */
  17. /* TODO: Abort logging when we get an error in reading or writing log files */
  18. #ifdef __EMX__
  19. #include <io.h>
  20. #endif
  21. #include "mysql_priv.h"
  22. #include "sql_acl.h"
  23. #include "sql_repl.h"
  24. #include <my_dir.h>
  25. #include <stdarg.h>
  26. #include <m_ctype.h> // For test_if_number
  27. MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
  28. extern I_List<i_string> binlog_do_db, binlog_ignore_db;
  29. extern ulong max_binlog_size;
  30. static bool test_if_number(const char *str,
  31.    long *res, bool allow_wildcards);
  32. /****************************************************************************
  33. ** Find a uniq filename for 'filename.#'.
  34. ** Set # to a number as low as possible
  35. ** returns != 0 if not possible to get uniq filename
  36. ****************************************************************************/
  37. static int find_uniq_filename(char *name)
  38. {
  39.   long number;
  40.   uint i,length;
  41.   char buff[FN_REFLEN];
  42.   struct st_my_dir *dir_info;
  43.   reg1 struct fileinfo *file_info;
  44.   ulong max_found=0;
  45.   DBUG_ENTER("find_uniq_filename");
  46.   length=dirname_part(buff,name);
  47.   char *start=name+length,*end=strend(start);
  48.   *end='.';
  49.   length= (uint) (end-start+1);
  50.   if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
  51.   { // This shouldn't happen
  52.     strmov(end,".1"); // use name+1
  53.     DBUG_RETURN(0);
  54.   }
  55.   file_info= dir_info->dir_entry;
  56.   for (i=dir_info->number_off_files ; i-- ; file_info++)
  57.   {
  58.     if (bcmp(file_info->name,start,length) == 0 &&
  59. test_if_number(file_info->name+length, &number,0))
  60.     {
  61.       set_if_bigger(max_found,(ulong) number);
  62.     }
  63.   }
  64.   my_dirend(dir_info);
  65.   *end++='.';
  66.   sprintf(end,"%03ld",max_found+1);
  67.   DBUG_RETURN(0);
  68. }
  69. MYSQL_LOG::MYSQL_LOG(): last_time(0), query_start(0),index_file(-1),
  70. name(0), log_type(LOG_CLOSED),write_error(0),
  71. inited(0), no_rotate(0)
  72. {
  73.   /*
  74.     We don't want to intialize LOCK_Log here as the thread system may
  75.     not have been initailized yet. We do it instead at 'open'.
  76.   */
  77.   index_file_name[0] = 0;
  78.   bzero((char*) &log_file,sizeof(log_file));
  79. }
  80. MYSQL_LOG::~MYSQL_LOG()
  81. {
  82.   if (inited)
  83.   {
  84.     (void) pthread_mutex_destroy(&LOCK_log);
  85.     (void) pthread_mutex_destroy(&LOCK_index);
  86.   }
  87. }
  88. void MYSQL_LOG::set_index_file_name(const char* index_file_name)
  89. {
  90.   if (index_file_name)
  91.     fn_format(this->index_file_name,index_file_name,mysql_data_home,"-index",
  92.       4);
  93.   else
  94.     this->index_file_name[0] = 0;
  95. }
  96. int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
  97. {      
  98.   if (log_type == LOG_NORMAL)
  99.     fn_format(new_name,log_name,mysql_data_home,"",4);
  100.   else
  101.   {
  102.     fn_format(new_name,log_name,mysql_data_home,"",4);
  103.     if (!fn_ext(log_name)[0])
  104.     {
  105.       if (find_uniq_filename(new_name))
  106.       {
  107. sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
  108. return 1;
  109.       }
  110.     }
  111.   }
  112.   return 0;
  113. }
  114. void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
  115.      const char *new_name)
  116. {
  117.   MY_STAT tmp_stat;
  118.   char buff[512];
  119.   File file= -1;
  120.   bool do_magic;
  121.   if (!inited)
  122.   {
  123.     inited=1;
  124.     (void) pthread_mutex_init(&LOCK_log,NULL);
  125.     (void) pthread_mutex_init(&LOCK_index, NULL);
  126.     if (log_type_arg == LOG_BIN && *fn_ext(log_name))
  127.       no_rotate = 1;
  128.   }
  129.   
  130.   log_type=log_type_arg;
  131.   if (!(name=my_strdup(log_name,MYF(MY_WME))))
  132.     goto err;
  133.   if (new_name)
  134.     strmov(log_file_name,new_name);
  135.   else if (generate_new_name(log_file_name, name))
  136.     goto err;
  137.   if (log_type == LOG_BIN && !index_file_name[0])
  138.     fn_format(index_file_name, name, mysql_data_home, ".index", 6);
  139.   
  140.   db[0]=0;
  141.   do_magic = ((log_type == LOG_BIN) && !my_stat(log_file_name,
  142. &tmp_stat, MYF(0)));
  143.   
  144.   if ((file=my_open(log_file_name,O_CREAT | O_APPEND | O_WRONLY | O_BINARY,
  145.     MYF(MY_WME | ME_WAITTANG))) < 0 ||
  146.       init_io_cache(&log_file, file, IO_SIZE, WRITE_CACHE,
  147.     my_tell(file,MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP)))
  148.     goto err;
  149.   if (log_type == LOG_NORMAL)
  150.   {
  151.     char *end;
  152. #ifdef __NT__
  153.     sprintf(buff, "%s, Version: %s, started with:nTCP Port: %d, Named Pipe: %sn", my_progname, server_version, mysql_port, mysql_unix_port);
  154. #else
  155.     sprintf(buff, "%s, Version: %s, started with:nTcp port: %d  Unix socket: %sn", my_progname,server_version,mysql_port,mysql_unix_port);
  156. #endif
  157.     end=strmov(strend(buff),"Time                 Id Command    Argumentn");
  158.     if (my_b_write(&log_file, (byte*) buff,(uint) (end-buff)) ||
  159. flush_io_cache(&log_file))
  160.       goto err;
  161.   }
  162.   else if (log_type == LOG_NEW)
  163.   {
  164.     time_t skr=time(NULL);
  165.     struct tm tm_tmp;
  166.     localtime_r(&skr,&tm_tmp);
  167.     sprintf(buff,"# %s, Version: %s at %02d%02d%02d %2d:%02d:%02dn",
  168.     my_progname,server_version,
  169.     tm_tmp.tm_year % 100,
  170.     tm_tmp.tm_mon+1,
  171.     tm_tmp.tm_mday,
  172.     tm_tmp.tm_hour,
  173.     tm_tmp.tm_min,
  174.     tm_tmp.tm_sec);
  175.     if (my_b_write(&log_file, (byte*) buff,(uint) strlen(buff)) ||
  176. flush_io_cache(&log_file))
  177.       goto err;
  178.   }
  179.   else if (log_type == LOG_BIN)
  180.   {
  181.     /*
  182.       Explanation of the boolean black magic:
  183.       if we are supposed to write magic number try write
  184.       clean up if failed
  185.       then if index_file has not been previously opened, try to open it
  186.       clean up if failed
  187.     */
  188.     if ((do_magic && my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4)) ||
  189. (index_file < 0 && 
  190.  (index_file = my_open(index_file_name,
  191.        O_APPEND | O_BINARY | O_RDWR | O_CREAT,
  192.        MYF(MY_WME))) < 0))
  193.       goto err;
  194.     Start_log_event s;
  195.     bool error;
  196.     s.write(&log_file);
  197.     flush_io_cache(&log_file);
  198.     pthread_mutex_lock(&LOCK_index);
  199.     error=(my_write(index_file, (byte*) log_file_name, strlen(log_file_name),
  200.     MYF(MY_NABP | MY_WME)) ||
  201.    my_write(index_file, (byte*) "n", 1, MYF(MY_NABP | MY_WME)));
  202.     pthread_mutex_unlock(&LOCK_index);
  203.     if (error)
  204.     {
  205.       my_close(index_file,MYF(0));
  206.       index_file= -1;
  207.       goto err;
  208.     }
  209.   }
  210.   return;
  211. err:
  212.   sql_print_error("Could not use %s for logging (error %d)", log_name,errno);
  213.   if (file >= 0)
  214.     my_close(file,MYF(0));
  215.   end_io_cache(&log_file);
  216.   x_free(name); name=0;
  217.   log_type=LOG_CLOSED;
  218.   return;
  219.   
  220. }
  221. int MYSQL_LOG::get_current_log(LOG_INFO* linfo)
  222. {
  223.   pthread_mutex_lock(&LOCK_log);
  224.   strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name)-1);
  225.   linfo->pos = my_b_tell(&log_file);
  226.   pthread_mutex_unlock(&LOCK_log);
  227.   return 0;
  228. }
  229. // if log_name is "" we stop at the first entry
  230. int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name)
  231. {
  232.   if (index_file < 0)
  233.     return LOG_INFO_INVALID;
  234.   int error = 0;
  235.   char* fname = linfo->log_file_name;
  236.   uint log_name_len = (uint) strlen(log_name);
  237.   IO_CACHE io_cache;
  238.   // mutex needed because we need to make sure the file pointer does not move
  239.   // from under our feet
  240.   pthread_mutex_lock(&LOCK_index);
  241.   if (init_io_cache(&io_cache, index_file, IO_SIZE, READ_CACHE, (my_off_t) 0,
  242.     0, MYF(MY_WME)))
  243.   {
  244.     error = LOG_INFO_SEEK;
  245.     goto err;
  246.   }
  247.   for(;;)
  248.   {
  249.     uint length;
  250.     if (!(length=my_b_gets(&io_cache, fname, FN_REFLEN-1)))
  251.     {
  252.       error = !io_cache.error ? LOG_INFO_EOF : LOG_INFO_IO;
  253.       goto err;
  254.     }
  255.     // if the log entry matches, empty string matching anything
  256.     if (!log_name_len ||
  257. (log_name_len == length-1 && fname[log_name_len] == 'n' &&
  258.  !memcmp(fname, log_name, log_name_len)))
  259.     {
  260.       fname[length-1]=0; // remove last n
  261.       linfo->index_file_offset = my_b_tell(&io_cache);
  262.       break;
  263.     }
  264.   }
  265.   error = 0;
  266. err:
  267.   pthread_mutex_unlock(&LOCK_index);
  268.   end_io_cache(&io_cache);
  269.   return error;
  270.      
  271. }
  272. int MYSQL_LOG::find_next_log(LOG_INFO* linfo)
  273. {
  274.   // mutex needed because we need to make sure the file pointer does not move
  275.   // from under our feet
  276.   if (index_file < 0) return LOG_INFO_INVALID;
  277.   int error = 0;
  278.   char* fname = linfo->log_file_name;
  279.   IO_CACHE io_cache;
  280.   uint length;
  281.   pthread_mutex_lock(&LOCK_index);
  282.   if (init_io_cache(&io_cache, index_file, IO_SIZE, 
  283.     READ_CACHE, (my_off_t) linfo->index_file_offset, 0,
  284.     MYF(MY_WME)))
  285.   {
  286.     error = LOG_INFO_SEEK;
  287.     goto err;
  288.   }
  289.   if (!(length=my_b_gets(&io_cache, fname, FN_REFLEN)))
  290.   {
  291.     error = !io_cache.error ? LOG_INFO_EOF : LOG_INFO_IO;
  292.     goto err;
  293.   }
  294.   fname[length-1]=0; // kill /n
  295.   linfo->index_file_offset = my_b_tell(&io_cache);
  296.   error = 0;
  297. err:
  298.   pthread_mutex_unlock(&LOCK_index);
  299.   end_io_cache(&io_cache);
  300.   return error;
  301. }
  302.  
  303. int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
  304. {
  305.   if (index_file < 0) return LOG_INFO_INVALID;
  306.   if (no_rotate) return LOG_INFO_PURGE_NO_ROTATE;
  307.   int error;
  308.   char fname[FN_REFLEN];
  309.   char *p;
  310.   uint fname_len, i;
  311.   bool logs_to_purge_inited = 0, logs_to_keep_inited = 0, found_log = 0;
  312.   DYNAMIC_ARRAY logs_to_purge, logs_to_keep;
  313.   my_off_t purge_offset ;
  314.   LINT_INIT(purge_offset);
  315.   IO_CACHE io_cache;
  316.   
  317.   pthread_mutex_lock(&LOCK_index);
  318.   
  319.   if (init_io_cache(&io_cache,index_file, IO_SIZE*2, READ_CACHE, (my_off_t) 0,
  320.     0, MYF(MY_WME)))
  321.   {
  322.     error = LOG_INFO_MEM;
  323.     goto err;
  324.   }
  325.   if (init_dynamic_array(&logs_to_purge, sizeof(char*), 1024, 1024))
  326.   {
  327.     error = LOG_INFO_MEM;
  328.     goto err;
  329.   }
  330.   logs_to_purge_inited = 1;
  331.   
  332.   if (init_dynamic_array(&logs_to_keep, sizeof(char*), 1024, 1024))
  333.   {
  334.     error = LOG_INFO_MEM;
  335.     goto err;
  336.   }
  337.   logs_to_keep_inited = 1;
  338.   
  339.   for(;;)
  340.   {
  341.     my_off_t init_purge_offset= my_b_tell(&io_cache);
  342.     if (!(fname_len=my_b_gets(&io_cache, fname, FN_REFLEN)))
  343.     {
  344.       if(!io_cache.error)
  345. break;
  346.       error = LOG_INFO_IO;
  347.       goto err;
  348.     }
  349.     fname[--fname_len]=0; // kill n
  350.     if(!memcmp(fname, to_log, fname_len + 1 ))
  351.     {
  352.       found_log = 1;
  353.       purge_offset = init_purge_offset;
  354.     }
  355.       
  356.     // if one of the logs before the target is in use
  357.     if(!found_log && log_in_use(fname))
  358.     {
  359.       error = LOG_INFO_IN_USE;
  360.       goto err;
  361.     }
  362.       
  363.     if (!(p = sql_memdup(fname, fname_len+1)) ||
  364. insert_dynamic(found_log ? &logs_to_keep : &logs_to_purge,
  365.        (gptr) &p))
  366.     {
  367.       error = LOG_INFO_MEM;
  368.       goto err;
  369.     }
  370.   }
  371.   
  372.   end_io_cache(&io_cache);
  373.   if(!found_log)
  374.   {
  375.     error = LOG_INFO_EOF;
  376.     goto err;
  377.   }
  378.   
  379.   for(i = 0; i < logs_to_purge.elements; i++)
  380.   {
  381.     char* l;
  382.     get_dynamic(&logs_to_purge, (gptr)&l, i);
  383.     if (my_delete(l, MYF(MY_WME)))
  384.       sql_print_error("Error deleting %s during purge", l);
  385.   }
  386.   
  387.   // if we get killed -9 here, the sysadmin would have to do a small
  388.   // vi job on the log index file after restart - otherwise, this should
  389.   // be safe
  390. #ifdef HAVE_FTRUNCATE
  391.   if (ftruncate(index_file,0))
  392.   {
  393.     sql_print_error("Could not truncate the binlog index file 
  394. during log purge for write");
  395.     error = LOG_INFO_FATAL;
  396.     goto err;
  397.   }
  398.   my_seek(index_file, 0, MY_SEEK_CUR,MYF(MY_WME));
  399. #else
  400.   my_close(index_file, MYF(MY_WME));
  401.   my_delete(index_file_name, MYF(MY_WME));
  402.   if(!(index_file = my_open(index_file_name,
  403.     O_CREAT | O_BINARY | O_RDWR | O_APPEND,
  404.     MYF(MY_WME))))
  405.   {
  406.     sql_print_error("Could not re-open the binlog index file 
  407. during log purge for write");
  408.     error = LOG_INFO_FATAL;
  409.     goto err;
  410.   }
  411. #endif
  412.   
  413.   for(i = 0; i < logs_to_keep.elements; i++)
  414.   {
  415.     char* l;
  416.     get_dynamic(&logs_to_keep, (gptr)&l, i);
  417.     if (my_write(index_file, (byte*) l, strlen(l), MYF(MY_WME|MY_NABP)) ||
  418. my_write(index_file, (byte*) "n", 1, MYF(MY_WME|MY_NABP)))
  419.     {
  420.       error = LOG_INFO_FATAL;
  421.       goto err;
  422.     }
  423.   }
  424.   // now update offsets
  425.   adjust_linfo_offsets(purge_offset);
  426.   error = 0;
  427. err:
  428.   pthread_mutex_unlock(&LOCK_index);
  429.   if(logs_to_purge_inited)
  430.     delete_dynamic(&logs_to_purge);
  431.   if(logs_to_keep_inited)
  432.     delete_dynamic(&logs_to_keep);
  433.   end_io_cache(&io_cache);
  434.   return error;
  435. }
  436. // we assume that buf has at least FN_REFLEN bytes alloced
  437. void MYSQL_LOG::make_log_name(char* buf, const char* log_ident)
  438. {
  439.   buf[0] = 0; // In case of error
  440.   if (inited)
  441.   {
  442.     int dir_len = dirname_length(log_file_name); 
  443.     int ident_len = (uint) strlen(log_ident);
  444.     if (dir_len + ident_len + 1 > FN_REFLEN)
  445.       return; // protection agains malicious buffer overflow
  446.       
  447.     memcpy(buf, log_file_name, dir_len);
  448.     // copy filename + end null
  449.     memcpy(buf + dir_len, log_ident, ident_len + 1);
  450.   }
  451. }
  452. bool MYSQL_LOG::is_active(const char* log_file_name)
  453. {
  454.   return inited && !strcmp(log_file_name, this->log_file_name);
  455. }
  456. void MYSQL_LOG::new_file()
  457. {
  458.   // only rotate open logs that are marked non-rotatable
  459.   // (binlog with constant name are non-rotatable)
  460.   if (is_open() && ! no_rotate)
  461.   {
  462.     char new_name[FN_REFLEN], *old_name=name;
  463.     VOID(pthread_mutex_lock(&LOCK_log));
  464.     if (generate_new_name(new_name, name))
  465.     {
  466.       VOID(pthread_mutex_unlock(&LOCK_log));
  467.       return; // Something went wrong
  468.     }
  469.     if (log_type == LOG_BIN)
  470.     {
  471.       /*
  472. We log the whole file name for log file as the user may decide
  473. to change base names at some point.
  474.       */
  475.       Rotate_log_event r(new_name+dirname_length(new_name));
  476.       r.write(&log_file);
  477.       VOID(pthread_cond_broadcast(&COND_binlog_update));
  478.     }
  479.     name=0;
  480.     close();
  481.     open(old_name, log_type, new_name);
  482.     my_free(old_name,MYF(0));
  483.     last_time=query_start=0;
  484.     write_error=0;
  485.     VOID(pthread_mutex_unlock(&LOCK_log));
  486.   }
  487. }
  488. bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
  489.       const char *format,...)
  490. {
  491.   if (is_open() && (what_to_log & (1L << (uint) command)))
  492.   {
  493.     int error=0;
  494.     VOID(pthread_mutex_lock(&LOCK_log));
  495.     /* Test if someone closed after the is_open test */
  496.     if (log_type != LOG_CLOSED)
  497.     {
  498.       time_t skr;
  499.       ulong id;
  500.       va_list args;
  501.       va_start(args,format);
  502.       char buff[32];
  503.       if (thd)
  504.       { // Normal thread
  505. if ((thd->options & OPTION_LOG_OFF) &&
  506.     (thd->master_access & PROCESS_ACL))
  507. {
  508.   VOID(pthread_mutex_unlock(&LOCK_log));
  509.   return 0; // No logging
  510. }
  511. id=thd->thread_id;
  512. if (thd->user_time || !(skr=thd->query_start()))
  513.   skr=time(NULL); // Connected
  514.       }
  515.       else
  516.       { // Log from connect handler
  517. skr=time(NULL);
  518. id=0;
  519.       }
  520.       if (skr != last_time)
  521.       {
  522. last_time=skr;
  523. struct tm tm_tmp;
  524. struct tm *start;
  525. localtime_r(&skr,&tm_tmp);
  526. start=&tm_tmp;
  527. /* Note that my_b_write() assumes it knows the length for this */
  528. sprintf(buff,"%02d%02d%02d %2d:%02d:%02dt",
  529. start->tm_year % 100,
  530. start->tm_mon+1,
  531. start->tm_mday,
  532. start->tm_hour,
  533. start->tm_min,
  534. start->tm_sec);
  535. if (my_b_write(&log_file, (byte*) buff,16))
  536.   error=errno;
  537.       }
  538.       else if (my_b_write(&log_file, (byte*) "tt",2) < 0)
  539. error=errno;
  540.       sprintf(buff,"%7ld %-11.11s", id,command_name[(uint) command]);
  541.       if (my_b_write(&log_file, (byte*) buff,strlen(buff)))
  542. error=errno;
  543.       if (format)
  544.       {
  545. if (my_b_write(&log_file, (byte*) " ",1) ||
  546.     my_b_vprintf(&log_file,format,args) == (uint) -1)
  547.   error=errno;
  548.       }
  549.       if (my_b_write(&log_file, (byte*) "n",1) ||
  550.   flush_io_cache(&log_file))
  551. error=errno;
  552.       if (error && ! write_error)
  553.       {
  554. write_error=1;
  555. sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
  556.       }
  557.       va_end(args);
  558.     }
  559.     VOID(pthread_mutex_unlock(&LOCK_log));
  560.     return error != 0;
  561.   }
  562.   return 0;
  563. }
  564. /* Write to binary log in a format to be used for replication */
  565. bool MYSQL_LOG::write(Query_log_event* event_info)
  566. {
  567.   /* In most cases this is only called if 'is_open()' is true */
  568.   bool error=0;
  569.   bool should_rotate = 0;
  570.   
  571.   if (!inited) // Can't use mutex if not init
  572.     return 0;
  573.   VOID(pthread_mutex_lock(&LOCK_log));
  574.   if (is_open())
  575.   {
  576.     THD *thd=event_info->thd;
  577.     IO_CACHE *file = (event_info->cache_stmt ? &thd->transaction.trans_log :
  578.       &log_file);
  579.     if ((!(thd->options & OPTION_BIN_LOG) &&
  580.  (thd->master_access & PROCESS_ACL)) ||
  581. !db_ok(event_info->db, binlog_do_db, binlog_ignore_db))
  582.     {
  583.       VOID(pthread_mutex_unlock(&LOCK_log));
  584.       return 0;
  585.     }
  586.     error=1;
  587.     if (thd->last_insert_id_used)
  588.     {
  589.       Intvar_log_event e((uchar)LAST_INSERT_ID_EVENT, thd->last_insert_id);
  590.       if (e.write(file))
  591. goto err;
  592.     }
  593.     if (thd->insert_id_used)
  594.     {
  595.       Intvar_log_event e((uchar)INSERT_ID_EVENT, thd->last_insert_id);
  596.       if (e.write(file))
  597. goto err;
  598.     }
  599.     if (thd->convert_set)
  600.     {
  601.       char buf[1024] = "SET CHARACTER SET ";
  602.       char* p = strend(buf);
  603.       p = strmov(p, thd->convert_set->name);
  604.       int save_query_length = thd->query_length;
  605.       // just in case somebody wants it later
  606.       thd->query_length = (uint)(p - buf);
  607.       Query_log_event e(thd, buf);
  608.       if (e.write(file))
  609. goto err;
  610.       thd->query_length = save_query_length; // clean up
  611.     }
  612.     if (event_info->write(file) ||
  613. file == &log_file && flush_io_cache(file))
  614.       goto err;
  615.     error=0;
  616.     should_rotate = (file == &log_file && my_b_tell(file) >= max_binlog_size); 
  617. err:
  618.     if (error)
  619.     {
  620.       if (my_errno == EFBIG)
  621. my_error(ER_TRANS_CACHE_FULL, MYF(0));
  622.       else
  623. my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
  624.       write_error=1;
  625.     }
  626.     if (file == &log_file)
  627.       VOID(pthread_cond_broadcast(&COND_binlog_update));
  628.   }
  629.   VOID(pthread_mutex_unlock(&LOCK_log));
  630.   if(should_rotate)
  631.     new_file();
  632.   return error;
  633. }
  634. /*
  635.   Write a cached log entry to the binary log
  636.   We only come here if there is something in the cache.
  637.   'cache' needs to be reinitialized after this functions returns.
  638. */
  639. bool MYSQL_LOG::write(IO_CACHE *cache)
  640. {
  641.   VOID(pthread_mutex_lock(&LOCK_log));
  642.   bool error=1;
  643.   
  644.   if (is_open())
  645.   {
  646.     uint length;
  647.     if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
  648.     {
  649.       sql_print_error(ER(ER_ERROR_ON_WRITE), cache->file_name, errno);
  650.       goto err;
  651.     }
  652.     length=my_b_bytes_in_cache(cache);
  653.     do
  654.     {
  655.       if (my_b_write(&log_file, cache->rc_pos, length))
  656.       {
  657. if (!write_error)
  658.   sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
  659. goto err;
  660.       }
  661.       cache->rc_pos=cache->rc_end; // Mark buffer used up
  662.     } while ((length=my_b_fill(cache)));
  663.     if (flush_io_cache(&log_file))
  664.     {
  665.       if (!write_error)
  666. sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
  667.       goto err;
  668.     }
  669.     if (cache->error) // Error on read
  670.     {
  671.       sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
  672.       goto err;
  673.     }
  674.   }
  675.   error=0;
  676. err:
  677.   if (error)
  678.     write_error=1;
  679.   else
  680.     VOID(pthread_cond_broadcast(&COND_binlog_update));
  681.     
  682.   VOID(pthread_mutex_unlock(&LOCK_log));
  683.   
  684.   return error;
  685. }
  686. bool MYSQL_LOG::write(Load_log_event* event_info)
  687. {
  688.   bool error=0;
  689.   bool should_rotate = 0;
  690.   
  691.   if (inited)
  692.   {
  693.     VOID(pthread_mutex_lock(&LOCK_log));
  694.     if (is_open())
  695.     {
  696.       THD *thd=event_info->thd;
  697.       if ((thd->options & OPTION_BIN_LOG) ||
  698.   !(thd->master_access & PROCESS_ACL))
  699.       {
  700. if (event_info->write(&log_file) || flush_io_cache(&log_file))
  701. {
  702.   if (!write_error)
  703.     sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
  704.   error=write_error=1;
  705. }
  706. should_rotate = (my_b_tell(&log_file) >= max_binlog_size);
  707. VOID(pthread_cond_broadcast(&COND_binlog_update));
  708.       }
  709.     }
  710.     VOID(pthread_mutex_unlock(&LOCK_log));
  711.   }
  712.   if(should_rotate)
  713.     new_file();
  714.   
  715.   return error;
  716. }
  717. /* Write update log in a format suitable for incremental backup */
  718. bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
  719.       time_t query_start)
  720. {
  721.   bool error=0;
  722.   if (is_open())
  723.   {
  724.     time_t current_time;
  725.     VOID(pthread_mutex_lock(&LOCK_log));
  726.     if (is_open())
  727.     { // Safety agains reopen
  728.       int tmp_errno=0;
  729.       char buff[80],*end;
  730.       end=buff;
  731.       if (!(thd->options & OPTION_UPDATE_LOG) &&
  732.   (thd->master_access & PROCESS_ACL))
  733.       {
  734. VOID(pthread_mutex_unlock(&LOCK_log));
  735. return 0;
  736.       }
  737.       if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start)
  738.       {
  739. current_time=time(NULL);
  740. if (current_time != last_time)
  741. {
  742.   last_time=current_time;
  743.   struct tm tm_tmp;
  744.   struct tm *start;
  745.   localtime_r(&current_time,&tm_tmp);
  746.   start=&tm_tmp;
  747.   /* Note that my_b_write() assumes it knows the length for this */
  748.   sprintf(buff,"# Time: %02d%02d%02d %2d:%02d:%02dn",
  749.   start->tm_year % 100,
  750.   start->tm_mon+1,
  751.   start->tm_mday,
  752.   start->tm_hour,
  753.   start->tm_min,
  754.   start->tm_sec);
  755.   if (my_b_write(&log_file, (byte*) buff,24))
  756.     tmp_errno=errno;
  757. }
  758. if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]n",
  759. thd->priv_user,
  760. thd->user,
  761. thd->host ? thd->host : "",
  762. thd->ip ? thd->ip : "") == (uint) -1)
  763.   tmp_errno=errno;
  764.       }
  765.       if (query_start)
  766.       {
  767. /* For slow query log */
  768. if (my_b_printf(&log_file,
  769. "# Time: %lu  Lock_time: %lu  Rows_sent: %lun",
  770. (ulong) (current_time - query_start),
  771. (ulong) (thd->time_after_lock - query_start),
  772. (ulong) thd->sent_row_count) == (uint) -1)
  773.     tmp_errno=errno;
  774.       }
  775.       if (thd->db && strcmp(thd->db,db))
  776.       { // Database changed
  777. if (my_b_printf(&log_file,"use %s;n",thd->db) == (uint) -1)
  778.   tmp_errno=errno;
  779. strmov(db,thd->db);
  780.       }
  781.       if (thd->last_insert_id_used)
  782.       {
  783. end=strmov(end,",last_insert_id=");
  784. end=longlong10_to_str((longlong) thd->current_insert_id,end,-10);
  785.       }
  786.       // Save value if we do an insert.
  787.       if (thd->insert_id_used)
  788.       {
  789. if (specialflag & SPECIAL_LONG_LOG_FORMAT)
  790. {
  791.   end=strmov(end,",insert_id=");
  792.   end=longlong10_to_str((longlong) thd->last_insert_id,end,-10);
  793. }
  794.       }
  795.       if (thd->query_start_used)
  796.       {
  797. if (query_start != thd->query_start())
  798. {
  799.   query_start=thd->query_start();
  800.   end=strmov(end,",timestamp=");
  801.   end=int10_to_str((long) query_start,end,10);
  802. }
  803.       }
  804.       if (end != buff)
  805.       {
  806. *end++=';';
  807. *end++='n';
  808. *end=0;
  809. if (my_b_write(&log_file, (byte*) "SET ",4) ||
  810.     my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)-1))
  811.   tmp_errno=errno;
  812.       }
  813.       if (!query)
  814.       {
  815. query="#adminstrator command";
  816. query_length=21;
  817.       }
  818.       if (my_b_write(&log_file, (byte*) query,query_length) ||
  819.   my_b_write(&log_file, (byte*) ";n",2) ||
  820.   flush_io_cache(&log_file))
  821. tmp_errno=errno;
  822.       if (tmp_errno)
  823.       {
  824. error=1;
  825. if (! write_error)
  826. {
  827.   write_error=1;
  828.   sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
  829. }
  830.       }
  831.     }
  832.     VOID(pthread_mutex_unlock(&LOCK_log));
  833.   }
  834.   return error;
  835. }
  836. void MYSQL_LOG::close(bool exiting)
  837. { // One can't set log_type here!
  838.   if (is_open())
  839.   {
  840.     File file=log_file.file;
  841.     if (log_type == LOG_BIN)
  842.     {
  843.       Stop_log_event s;
  844.       s.write(&log_file);
  845.       VOID(pthread_cond_broadcast(&COND_binlog_update));
  846.     }
  847.     end_io_cache(&log_file);
  848.     if (my_close(file,MYF(0)) < 0 && ! write_error)
  849.     {
  850.       write_error=1;
  851.       sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
  852.     }
  853.   }
  854.   if (exiting && index_file >= 0)
  855.   {
  856.     if (my_close(index_file,MYF(0)) < 0 && ! write_error)
  857.     {
  858.       write_error=1;
  859.       sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno);
  860.     }
  861.     index_file=-1;
  862.     log_type=LOG_CLOSED;
  863.   }
  864.   safeFree(name);
  865. }
  866. /* Check if a string is a valid number */
  867. /* Output: TRUE -> number */
  868. static bool test_if_number(register const char *str,
  869.    long *res, bool allow_wildcards)
  870. {
  871.   reg2 int flag;
  872.   const char *start;
  873.   DBUG_ENTER("test_if_number");
  874.   flag=0; start=str;
  875.   while (*str++ == ' ') ;
  876.   if (*--str == '-' || *str == '+')
  877.     str++;
  878.   while (isdigit(*str) || (allow_wildcards &&
  879.    (*str == wild_many || *str == wild_one)))
  880.   {
  881.     flag=1;
  882.     str++;
  883.   }
  884.   if (*str == '.')
  885.   {
  886.     for (str++ ;
  887.  isdigit(*str) ||
  888.    (allow_wildcards && (*str == wild_many || *str == wild_one)) ;
  889.  str++, flag=1) ;
  890.   }
  891.   if (*str != 0 || flag == 0)
  892.     DBUG_RETURN(0);
  893.   if (res)
  894.     *res=atol(start);
  895.   DBUG_RETURN(1); /* Number ok */
  896. } /* test_if_number */
  897. void sql_print_error(const char *format,...)
  898. {
  899.   va_list args;
  900.   time_t skr;
  901.   struct tm tm_tmp;
  902.   struct tm *start;
  903.   va_start(args,format);
  904.   DBUG_ENTER("sql_print_error");
  905.   VOID(pthread_mutex_lock(&LOCK_error_log));
  906. #ifndef DBUG_OFF
  907.   {
  908.     char buff[1024];
  909.     my_vsnprintf(buff,sizeof(buff)-1,format,args);
  910.     DBUG_PRINT("error",("%s",buff));
  911.   }
  912. #endif
  913.   skr=time(NULL);
  914.   localtime_r(&skr,&tm_tmp);
  915.   start=&tm_tmp;
  916.   fprintf(stderr,"%02d%02d%02d %2d:%02d:%02d  ",
  917.   start->tm_year % 100,
  918.   start->tm_mon+1,
  919.   start->tm_mday,
  920.   start->tm_hour,
  921.   start->tm_min,
  922.   start->tm_sec);
  923.   (void) vfprintf(stderr,format,args);
  924.   (void) fputc('n',stderr);
  925.   fflush(stderr);
  926.   va_end(args);
  927.   VOID(pthread_mutex_unlock(&LOCK_error_log));
  928.   DBUG_VOID_RETURN;
  929. }
  930. void sql_perror(const char *message)
  931. {
  932. #ifdef HAVE_STRERROR
  933.   sql_print_error("%s: %s",message, strerror(errno));
  934. #else
  935.   perror(message);
  936. #endif
  937. }