1 /* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef LOG_H
24 #define LOG_H
25 
26 #include "unireg.h"                    // REQUIRED: for other includes
27 #include "handler.h"                            /* my_xid */
28 
29 /**
30   the struct aggregates two paramenters that identify an event
31   uniquely in scope of communication of a particular master and slave couple.
32   I.e there can not be 2 events from the same staying connected master which
33   have the same coordinates.
34   @note
35   Such identifier is not yet unique generally as the event originating master
36   is resetable. Also the crashed master can be replaced with some other.
37 */
38 typedef struct event_coordinates
39 {
40   char * file_name; // binlog file name (directories stripped)
41   my_off_t  pos;       // event's position in the binlog file
42 } LOG_POS_COORD;
43 
44 /**
45   Transaction Coordinator Log.
46 
47   A base abstract class for three different implementations of the
48   transaction coordinator.
49 
50   The server uses the transaction coordinator to order transactions
51   correctly and there are three different implementations: one using
52   an in-memory structure, one dummy that does not do anything, and one
53   using the binary log for transaction coordination.
54 */
55 class TC_LOG
56 {
57   public:
58   int using_heuristic_recover();
TC_LOG()59   TC_LOG() {}
~TC_LOG()60   virtual ~TC_LOG() {}
61 
62   enum enum_result {
63     RESULT_SUCCESS,
64     RESULT_ABORTED,
65     RESULT_INCONSISTENT
66   };
67 
68   virtual int open(const char *opt_name)=0;
69   virtual void close()=0;
70 
71   /**
72      Log a commit record of the transaction to the transaction
73      coordinator log.
74 
75      When the function returns, the transaction commit is properly
76      logged to the transaction coordinator log and can be committed in
77      the storage engines.
78 
79      @param thd Session to log transaction for.
80      @param all @c True if this is a "real" commit, @c false if it is a "statement" commit.
81 
82      @return Error code on failure, zero on success.
83    */
84   virtual enum_result commit(THD *thd, bool all) = 0;
85 
86   /**
87      Log a rollback record of the transaction to the transaction
88      coordinator log.
89 
90      When the function returns, the transaction have been aborted in
91      the transaction coordinator log.
92 
93      @param thd Session to log transaction record for.
94 
95      @param all @c true if an explicit commit or an implicit commit
96      for a statement, @c false if an internal commit of the statement.
97 
98      @return Error code on failure, zero on success.
99    */
100   virtual int rollback(THD *thd, bool all) = 0;
101   /**
102      Log a prepare record of the transaction to the storage engines.
103 
104      @param thd Session to log transaction record for.
105 
106      @param all @c true if an explicit commit or an implicit commit
107      for a statement, @c false if an internal commit of the statement.
108 
109      @return Error code on failure, zero on success.
110    */
111   virtual int prepare(THD *thd, bool all) = 0;
112 };
113 
114 
115 class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
116 {
117 public:
TC_LOG_DUMMY()118   TC_LOG_DUMMY() {}
open(const char * opt_name)119   int open(const char *opt_name)        { return 0; }
close()120   void close()                          { }
commit(THD * thd,bool all)121   enum_result commit(THD *thd, bool all) {
122     return ha_commit_low(thd, all) ? RESULT_ABORTED : RESULT_SUCCESS;
123   }
rollback(THD * thd,bool all)124   int rollback(THD *thd, bool all) {
125     return ha_rollback_low(thd, all);
126   }
prepare(THD * thd,bool all)127   int prepare(THD *thd, bool all) {
128     return ha_prepare_low(thd, all);
129   }
130 };
131 
132 #ifdef HAVE_MMAP
133 class TC_LOG_MMAP: public TC_LOG
134 {
135   public:                // only to keep Sun Forte on sol9x86 happy
136   typedef enum {
137     PS_POOL,                 // page is in pool
138     PS_ERROR,                // last sync failed
139     PS_DIRTY                 // new xids added since last sync
140   } PAGE_STATE;
141 
142   private:
143   typedef struct st_page {
144     struct st_page *next; // page a linked in a fifo queue
145     my_xid *start, *end;  // usable area of a page
146     my_xid *ptr;          // next xid will be written here
147     int size, free;       // max and current number of free xid slots on the page
148     int waiters;          // number of waiters on condition
149     PAGE_STATE state;     // see above
150     mysql_mutex_t lock; // to access page data or control structure
151     mysql_cond_t  cond; // to wait for a sync
152   } PAGE;
153 
154   char logname[FN_REFLEN];
155   File fd;
156   my_off_t file_length;
157   uint npages, inited;
158   uchar *data;
159   struct st_page *pages, *syncing, *active, *pool, *pool_last;
160   /*
161     note that, e.g. LOCK_active is only used to protect
162     'active' pointer, to protect the content of the active page
163     one has to use active->lock.
164     Same for LOCK_pool and LOCK_sync
165   */
166   mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync;
167   mysql_cond_t COND_pool, COND_active;
168 
169   public:
TC_LOG_MMAP()170   TC_LOG_MMAP(): inited(0) {}
171   int open(const char *opt_name);
172   void close();
173   enum_result commit(THD *thd, bool all);
rollback(THD * thd,bool all)174   int rollback(THD *thd, bool all)      { return ha_rollback_low(thd, all); }
prepare(THD * thd,bool all)175   int prepare(THD *thd, bool all)       { return ha_prepare_low(thd, all); }
176   int recover();
177 
178 private:
179   int log_xid(THD *thd, my_xid xid);
180   int unlog(ulong cookie, my_xid xid);
181   void get_active_from_pool();
182   int sync();
183   int overflow();
184 };
185 #else
186 #define TC_LOG_MMAP TC_LOG_DUMMY
187 #endif
188 
189 extern TC_LOG *tc_log;
190 extern TC_LOG_MMAP tc_log_mmap;
191 extern TC_LOG_DUMMY tc_log_dummy;
192 
193 /* log info errors */
194 #define LOG_INFO_EOF -1
195 #define LOG_INFO_IO  -2
196 #define LOG_INFO_INVALID -3
197 #define LOG_INFO_SEEK -4
198 #define LOG_INFO_MEM -6
199 #define LOG_INFO_FATAL -7
200 #define LOG_INFO_IN_USE -8
201 #define LOG_INFO_EMFILE -9
202 
203 
204 /* bitmap to SQL_LOG::close() */
205 #define LOG_CLOSE_INDEX		1
206 #define LOG_CLOSE_TO_BE_OPENED	2
207 #define LOG_CLOSE_STOP_EVENT	4
208 
209 /*
210   Maximum unique log filename extension.
211   Note: setting to 0x7FFFFFFF due to atol windows
212         overflow/truncate.
213  */
214 #define MAX_LOG_UNIQUE_FN_EXT 0x7FFFFFFF
215 
216 /*
217    Number of warnings that will be printed to error log
218    before extension number is exhausted.
219 */
220 #define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000
221 
222 /* max size of log messages (error log, plugins' logging, general log) */
223 #define MAX_LOG_BUFFER_SIZE 1024
224 #define MAX_TIME_SIZE 32
225 
226 #ifdef HAVE_PSI_INTERFACE
227 extern PSI_mutex_key key_LOG_INFO_lock;
228 #endif
229 
230 /*
231   Note that we destroy the lock mutex in the desctructor here.
232   This means that object instances cannot be destroyed/go out of scope,
233   until we have reset thd->current_linfo to NULL;
234  */
235 typedef struct st_log_info
236 {
237   char log_file_name[FN_REFLEN];
238   my_off_t index_file_offset, index_file_start_offset;
239   my_off_t pos;
240   bool fatal; // if the purge happens to give us a negative offset
241   int entry_index; //used in purge_logs(), calculatd in find_log_pos().
242   mysql_mutex_t lock;
st_log_infost_log_info243   st_log_info()
244     : index_file_offset(0), index_file_start_offset(0),
245       pos(0), fatal(0), entry_index(0)
246     {
247       log_file_name[0] = '\0';
248       mysql_mutex_init(key_LOG_INFO_lock, &lock, MY_MUTEX_INIT_FAST);
249     }
~st_log_infost_log_info250   ~st_log_info() { mysql_mutex_destroy(&lock);}
251 } LOG_INFO;
252 
253 /*
254   Currently we have only 3 kinds of logging functions: old-fashioned
255   logs, stdout and csv logging routines.
256 */
257 #define MAX_LOG_HANDLERS_NUM 3
258 
259 /* log event handler flags */
260 #define LOG_NONE       1
261 #define LOG_FILE       2
262 #define LOG_TABLE      4
263 
264 enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN };
265 enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED };
266 
267 /*
268   TODO use mmap instead of IO_CACHE for binlog
269   (mmap+fsync is two times faster than write+fsync)
270 */
271 
272 class MYSQL_LOG
273 {
274 public:
275   MYSQL_LOG();
276   void init_pthread_objects();
277   void cleanup();
278   bool open(
279 #ifdef HAVE_PSI_INTERFACE
280             PSI_file_key log_file_key,
281 #endif
282             const char *log_name,
283             enum_log_type log_type,
284             const char *new_name,
285             enum cache_type io_cache_type_arg);
286   bool init_and_set_log_file_name(const char *log_name,
287                                   const char *new_name,
288                                   enum_log_type log_type_arg,
289                                   enum cache_type io_cache_type_arg);
290   void init(enum_log_type log_type_arg,
291             enum cache_type io_cache_type_arg);
292   void close(uint exiting);
is_open()293   inline bool is_open() { return log_state != LOG_CLOSED; }
294   const char *generate_name(const char *log_name, const char *suffix,
295                             bool strip_ext, char *buff);
296   int generate_new_name(char *new_name, const char *log_name);
297  protected:
298   /* LOCK_log is inited by init_pthread_objects() */
299   mysql_mutex_t LOCK_log;
300   char *name;
301   char log_file_name[FN_REFLEN];
302   char time_buff[20], db[NAME_LEN + 1];
303   bool write_error, inited;
304   IO_CACHE log_file;
305   enum_log_type log_type;
306   volatile enum_log_state log_state;
307   enum cache_type io_cache_type;
308   friend class Log_event;
309 #ifdef HAVE_PSI_INTERFACE
310   /** Instrumentation key to use for file io in @c log_file */
311   PSI_file_key m_log_file_key;
312   /** The instrumentation key to use for @ LOCK_log. */
313   PSI_mutex_key m_key_LOCK_log;
314 #endif
315 };
316 
317 
318 enum enum_general_log_table_field
319 {
320   GLT_FIELD_EVENT_TIME = 0,
321   GLT_FIELD_USER_HOST,
322   GLT_FIELD_THREAD_ID,
323   GLT_FIELD_SERVER_ID,
324   GLT_FIELD_COMMAND_TYPE,
325   GLT_FIELD_ARGUMENT,
326   GLT_FIELD_COUNT
327 };
328 
329 
330 enum enum_slow_query_log_table_field
331 {
332   SQLT_FIELD_START_TIME = 0,
333   SQLT_FIELD_USER_HOST,
334   SQLT_FIELD_QUERY_TIME,
335   SQLT_FIELD_LOCK_TIME,
336   SQLT_FIELD_ROWS_SENT,
337   SQLT_FIELD_ROWS_EXAMINED,
338   SQLT_FIELD_DATABASE,
339   SQLT_FIELD_LAST_INSERT_ID,
340   SQLT_FIELD_INSERT_ID,
341   SQLT_FIELD_SERVER_ID,
342   SQLT_FIELD_SQL_TEXT,
343   SQLT_FIELD_THREAD_ID,
344   SQLT_FIELD_COUNT
345 };
346 
347 
348 class MYSQL_QUERY_LOG: public MYSQL_LOG
349 {
350 public:
MYSQL_QUERY_LOG()351   MYSQL_QUERY_LOG() : last_time(0) {}
352   bool reopen_file();
353   bool write(time_t event_time, const char *user_host,
354              uint user_host_len, my_thread_id thread_id,
355              const char *command_type, uint command_type_len,
356              const char *sql_text, uint sql_text_len);
357   bool write(THD *thd, time_t current_time, time_t query_start_arg,
358              const char *user_host, uint user_host_len,
359              ulonglong query_utime, ulonglong lock_utime, bool is_command,
360              const char *sql_text, uint sql_text_len);
open_slow_log(const char * log_name)361   bool open_slow_log(const char *log_name)
362   {
363     char buf[FN_REFLEN];
364     return open(
365 #ifdef HAVE_PSI_INTERFACE
366                 key_file_slow_log,
367 #endif
368                 generate_name(log_name, "-slow.log", 0, buf),
369                 LOG_NORMAL, 0, WRITE_CACHE);
370   }
open_query_log(const char * log_name)371   bool open_query_log(const char *log_name)
372   {
373     char buf[FN_REFLEN];
374     return open(
375 #ifdef HAVE_PSI_INTERFACE
376                 key_file_query_log,
377 #endif
378                 generate_name(log_name, ".log", 0, buf),
379                 LOG_NORMAL, 0, WRITE_CACHE);
380   }
381 
382 private:
383   time_t last_time;
384 };
385 
386 class Log_event_handler
387 {
388 public:
Log_event_handler()389   Log_event_handler() {}
390   virtual bool init()= 0;
391   virtual void cleanup()= 0;
392 
393   virtual bool log_slow(THD *thd, time_t current_time,
394                         time_t query_start_arg, const char *user_host,
395                         uint user_host_len, ulonglong query_utime,
396                         ulonglong lock_utime, bool is_command,
397                         const char *sql_text, uint sql_text_len)= 0;
398   virtual bool log_error(enum loglevel level, const char *format,
399                          va_list args)= 0;
400   virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
401                            uint user_host_len, my_thread_id thread_id,
402                            const char *command_type, uint command_type_len,
403                            const char *sql_text, uint sql_text_len,
404                            const CHARSET_INFO *client_cs)= 0;
~Log_event_handler()405   virtual ~Log_event_handler() {}
406 };
407 
408 
409 int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
410                        const char *table_name, bool check_if_opened);
411 
412 class Log_to_csv_event_handler: public Log_event_handler
413 {
414 public:
415   Log_to_csv_event_handler();
416   ~Log_to_csv_event_handler();
417   virtual bool init();
418   virtual void cleanup();
419 
420   virtual bool log_slow(THD *thd, time_t current_time,
421                         time_t query_start_arg, const char *user_host,
422                         uint user_host_len, ulonglong query_utime,
423                         ulonglong lock_utime, bool is_command,
424                         const char *sql_text, uint sql_text_len);
425   virtual bool log_error(enum loglevel level, const char *format,
426                          va_list args);
427   virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
428                            uint user_host_len, my_thread_id thread_id,
429                            const char *command_type, uint command_type_len,
430                            const char *sql_text, uint sql_text_len,
431                            const CHARSET_INFO *client_cs);
432 
433   int activate_log(THD *thd, uint log_type);
434 };
435 
436 
437 /* type of the log table */
438 #define QUERY_LOG_SLOW 1
439 #define QUERY_LOG_GENERAL 2
440 
441 class Log_to_file_event_handler: public Log_event_handler
442 {
443   MYSQL_QUERY_LOG mysql_log;
444   MYSQL_QUERY_LOG mysql_slow_log;
445   bool is_initialized;
446 public:
Log_to_file_event_handler()447   Log_to_file_event_handler(): is_initialized(FALSE)
448   {}
449   virtual bool init();
450   virtual void cleanup();
451 
452   virtual bool log_slow(THD *thd, time_t current_time,
453                         time_t query_start_arg, const char *user_host,
454                         uint user_host_len, ulonglong query_utime,
455                         ulonglong lock_utime, bool is_command,
456                         const char *sql_text, uint sql_text_len);
457   virtual bool log_error(enum loglevel level, const char *format,
458                          va_list args);
459   virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
460                            uint user_host_len, my_thread_id thread_id,
461                            const char *command_type, uint command_type_len,
462                            const char *sql_text, uint sql_text_len,
463                            const CHARSET_INFO *client_cs);
464   void flush();
465   void init_pthread_objects();
get_mysql_slow_log()466   MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; }
get_mysql_log()467   MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; }
468 };
469 
470 
471 /* Class which manages slow, general and error log event handlers */
472 class LOGGER
473 {
474   mysql_rwlock_t LOCK_logger;
475   /* flag to check whether logger mutex is initialized */
476   uint inited;
477 
478   /* available log handlers */
479   Log_to_csv_event_handler *table_log_handler;
480   Log_to_file_event_handler *file_log_handler;
481 
482   /* NULL-terminated arrays of log handlers */
483   Log_event_handler *error_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
484   Log_event_handler *slow_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
485   Log_event_handler *general_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
486 
487 public:
488 
489   bool is_log_tables_initialized;
490 
LOGGER()491   LOGGER() : inited(0), table_log_handler(NULL),
492              file_log_handler(NULL), is_log_tables_initialized(FALSE)
493   {}
lock_shared()494   void lock_shared() { mysql_rwlock_rdlock(&LOCK_logger); }
lock_exclusive()495   void lock_exclusive() { mysql_rwlock_wrlock(&LOCK_logger); }
unlock()496   void unlock() { mysql_rwlock_unlock(&LOCK_logger); }
497   bool is_log_table_enabled(uint log_table_type);
498   bool log_command(THD *thd, enum enum_server_command command,
499                    const char *query_str, size_t query_length);
500 
501   /*
502     We want to initialize all log mutexes as soon as possible,
503     but we cannot do it in constructor, as safe_mutex relies on
504     initialization, performed by MY_INIT(). This why this is done in
505     this function.
506   */
507   void init_base();
508   void init_log_tables();
509   bool flush_logs(THD *thd);
510   bool flush_slow_log();
511   bool flush_general_log();
512   /* Perform basic logger cleanup. this will leave e.g. error log open. */
513   void cleanup_base();
514   /* Free memory. Nothing could be logged after this function is called */
515   void cleanup_end();
516   bool error_log_print(enum loglevel level, const char *format,
517                       va_list args);
518   bool slow_log_print(THD *thd, const char *query, uint query_length);
519   bool general_log_print(THD *thd,enum enum_server_command command,
520                          const char *format, va_list args);
521   bool general_log_write(THD *thd, enum enum_server_command command,
522                          const char *query, uint query_length);
523 
524   /* we use this function to setup all enabled log event handlers */
525   int set_handlers(uint error_log_printer,
526                    uint slow_log_printer,
527                    uint general_log_printer);
528   void init_error_log(uint error_log_printer);
529   void init_slow_log(uint slow_log_printer);
530   void init_general_log(uint general_log_printer);
531   void deactivate_log_handler(THD* thd, uint log_type);
532   bool activate_log_handler(THD* thd, uint log_type);
get_slow_log_file_handler()533   MYSQL_QUERY_LOG *get_slow_log_file_handler() const
534   {
535     if (file_log_handler)
536       return file_log_handler->get_mysql_slow_log();
537     return NULL;
538   }
get_log_file_handler()539   MYSQL_QUERY_LOG *get_log_file_handler() const
540   {
541     if (file_log_handler)
542       return file_log_handler->get_mysql_log();
543     return NULL;
544   }
545 };
546 
547 enum enum_binlog_row_image {
548   /** PKE in the before image and changed columns in the after image */
549   BINLOG_ROW_IMAGE_MINIMAL= 0,
550   /** Whenever possible, before and after image contain all columns except blobs. */
551   BINLOG_ROW_IMAGE_NOBLOB= 1,
552   /** All columns in both before and after image. */
553   BINLOG_ROW_IMAGE_FULL= 2
554 };
555 
556 enum enum_binlog_format {
557   BINLOG_FORMAT_MIXED= 0, ///< statement if safe, otherwise row - autodetected
558   BINLOG_FORMAT_STMT=  1, ///< statement-based
559   BINLOG_FORMAT_ROW=   2, ///< row-based
560   BINLOG_FORMAT_UNSPEC=3  ///< thd_binlog_format() returns it when binlog is closed
561 };
562 
563 void exec_binlog_error_action_abort(const char* err_string);
564 int query_error_code(THD *thd, bool not_killed);
565 uint purge_log_get_error_code(int res);
566 
567 int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
568 void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
569 void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
570 void sql_print_information(const char *format, ...)
571   ATTRIBUTE_FORMAT(printf, 1, 2);
572 typedef void (*sql_print_message_func)(const char *format, ...)
573   ATTRIBUTE_FORMAT_FPTR(printf, 1, 2);
574 extern sql_print_message_func sql_print_message_handlers[];
575 
576 int error_log_print(enum loglevel level, const char *format,
577                     va_list args);
578 
579 bool slow_log_print(THD *thd, const char *query, uint query_length);
580 
581 bool general_log_print(THD *thd, enum enum_server_command command,
582                        const char *format,...);
583 
584 bool general_log_write(THD *thd, enum enum_server_command command,
585                        const char *query, uint query_length);
586 
587 void sql_perror(const char *message);
588 bool flush_error_log();
589 
590 char *make_log_name(char *buff, const char *name, const char* log_ext);
591 
592 /**
593   Check given log name against certain blacklisted names/extensions.
594 
595   @param name     Log name to check
596   @param len      Length of log name
597 
598   @returns true if name is valid, false otherwise.
599 */
600 bool is_valid_log_name(const char *name, size_t len);
601 
602 extern LOGGER logger;
603 
604 #endif /* LOG_H */
605