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