diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 2aeb19207de54..bcaeeadcd3d93 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -437,9 +437,11 @@ extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(THD* thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; my_time_t thd_TIME_to_gmt_sec(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(THD* thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } extern "C" { typedef enum _thd_wait_type_e { diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 08e6b91ed9044..64ea10f9c24ef 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -437,9 +437,11 @@ extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(THD* thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; my_time_t thd_TIME_to_gmt_sec(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(THD* thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } extern "C" { typedef enum _thd_wait_type_e { diff --git a/include/mysql/plugin_data_type.h.pp b/include/mysql/plugin_data_type.h.pp index 41b68c66fab42..592f4c443a755 100644 --- a/include/mysql/plugin_data_type.h.pp +++ b/include/mysql/plugin_data_type.h.pp @@ -437,9 +437,11 @@ extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(THD* thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; my_time_t thd_TIME_to_gmt_sec(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(THD* thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } extern "C" { typedef enum _thd_wait_type_e { diff --git a/include/mysql/plugin_encryption.h.pp b/include/mysql/plugin_encryption.h.pp index bbe46404fa15d..daad6df070dea 100644 --- a/include/mysql/plugin_encryption.h.pp +++ b/include/mysql/plugin_encryption.h.pp @@ -437,9 +437,11 @@ extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(THD* thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; my_time_t thd_TIME_to_gmt_sec(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(THD* thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } extern "C" { typedef enum _thd_wait_type_e { diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index 06de1668e7658..f47786096c4b0 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -437,9 +437,11 @@ extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(THD* thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; my_time_t thd_TIME_to_gmt_sec(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(THD* thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } extern "C" { typedef enum _thd_wait_type_e { diff --git a/include/mysql/plugin_function.h.pp b/include/mysql/plugin_function.h.pp index d56255818bfd2..fcb182a108351 100644 --- a/include/mysql/plugin_function.h.pp +++ b/include/mysql/plugin_function.h.pp @@ -437,9 +437,11 @@ extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(THD* thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; my_time_t thd_TIME_to_gmt_sec(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(THD* thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } extern "C" { typedef enum _thd_wait_type_e { diff --git a/include/mysql/plugin_password_validation.h.pp b/include/mysql/plugin_password_validation.h.pp index 529f50e26894c..11c8b07cf64ca 100644 --- a/include/mysql/plugin_password_validation.h.pp +++ b/include/mysql/plugin_password_validation.h.pp @@ -437,9 +437,11 @@ extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(THD* thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; my_time_t thd_TIME_to_gmt_sec(THD* thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(THD* thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(THD* thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } extern "C" { typedef enum _thd_wait_type_e { diff --git a/include/mysql/service_thd_timezone.h b/include/mysql/service_thd_timezone.h index 667137745f4c9..f3f2867f3261b 100644 --- a/include/mysql/service_thd_timezone.h +++ b/include/mysql/service_thd_timezone.h @@ -48,6 +48,7 @@ extern "C" { extern struct thd_timezone_service_st { my_time_t (*thd_TIME_to_gmt_sec)(MYSQL_THD thd, const MYSQL_TIME *ltime, unsigned int *errcode); void (*thd_gmt_sec_to_TIME)(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t); + void (*thd_TIME_to_str)(MYSQL_THD thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); } *thd_timezone_service; #ifdef MYSQL_DYNAMIC_PLUGIN @@ -58,10 +59,14 @@ extern struct thd_timezone_service_st { #define thd_gmt_sec_to_TIME(thd, ltime, t) \ (thd_timezone_service->thd_gmt_sec_to_TIME((thd), (ltime), (t))) +#define thd_TIME_to_str(thd, ltime, format, buf, buf_len) \ + (thd_timezone_service->thd_TIME_to_str((thd), (ltime), (format), (buf), (buf_len))) + #else my_time_t thd_TIME_to_gmt_sec(MYSQL_THD thd, const MYSQL_TIME *ltime, unsigned int *errcode); void thd_gmt_sec_to_TIME(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t); +void thd_TIME_to_str(MYSQL_THD thd, const MYSQL_TIME *ltime, const char *format, char *buf, unsigned int buf_len); #endif diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 9276a38bde4ef..cdb73908af4c2 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -18,6 +18,7 @@ server_audit_syslog_facility LOG_USER server_audit_syslog_ident mysql-server_auditing server_audit_syslog_info server_audit_syslog_priority LOG_INFO +server_audit_timestamp_format %Y%m%d %H:%i:%s set global server_audit_file_path=null; set global server_audit_incl_users=null; set global server_audit_file_path='server_audit.log'; @@ -104,6 +105,7 @@ server_audit_syslog_facility LOG_USER server_audit_syslog_ident mysql-server_auditing server_audit_syslog_info server_audit_syslog_priority LOG_INFO +server_audit_timestamp_format %Y%m%d %H:%i:%s set global server_audit_mode=1; set global server_audit_events=''; create database sa_db; @@ -380,6 +382,7 @@ server_audit_syslog_facility LOG_USER server_audit_syslog_ident mysql-server_auditing server_audit_syslog_info server_audit_syslog_priority LOG_INFO +server_audit_timestamp_format %Y%m%d %H:%i:%s uninstall plugin server_audit; Warnings: Warning 1620 Plugin is busy and will be uninstalled on shutdown diff --git a/mysql-test/suite/plugins/r/server_audit_buffering.result b/mysql-test/suite/plugins/r/server_audit_buffering.result index 9d4c27a726234..f2871a731872c 100644 --- a/mysql-test/suite/plugins/r/server_audit_buffering.result +++ b/mysql-test/suite/plugins/r/server_audit_buffering.result @@ -19,6 +19,7 @@ server_audit_syslog_facility LOG_USER server_audit_syslog_ident mysql-server_auditing server_audit_syslog_info server_audit_syslog_priority LOG_INFO +server_audit_timestamp_format %Y%m%d %H:%i:%s set global server_audit_logging=on; set global server_audit_sync_log_file=on; Line count in file: 52 diff --git a/mysql-test/suite/plugins/r/server_audit_query_id.result b/mysql-test/suite/plugins/r/server_audit_query_id.result index 3d2d9f18cc21d..3c0bf956a21c3 100644 --- a/mysql-test/suite/plugins/r/server_audit_query_id.result +++ b/mysql-test/suite/plugins/r/server_audit_query_id.result @@ -39,31 +39,31 @@ DROP TABLE source, dest, dest_2; set global server_audit_logging=off; # Wait for audit events to be written FOUND 1 /set global server_audit_logging=off/ in server_audit_query_id.log -TIMESTAMP,HOSTNAME,root,localhost,4,0,QUERY,test,'set global server_audit_logging=on',0 -TIMESTAMP,HOSTNAME,root,localhost,4,1,QUERY,test,'USE test',0 -TIMESTAMP,HOSTNAME,root,localhost,4,2,QUERY,test,'CREATE TABLE source (\nid bigint(20) NOT NULL AUTO_INCREMENT,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',0 -TIMESTAMP,HOSTNAME,root,localhost,4,3,QUERY,test,'CREATE TABLE dest (\nid bigint(20) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',0 -TIMESTAMP,HOSTNAME,root,localhost,4,4,QUERY,test,'CREATE TABLE dest_2 (\nid bigint(20) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',0 -TIMESTAMP,HOSTNAME,root,localhost,4,5,QUERY,test,'CREATE TRIGGER test_trigger\nAFTER INSERT ON source\nFOR EACH ROW\nINSERT INTO dest (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,6,QUERY,test,'CREATE TRIGGER test_trigger_2\nAFTER INSERT ON dest\nFOR EACH ROW\nINSERT INTO dest_2 (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,7,QUERY,test,'CREATE PROCEDURE test_procedure (IN id bigint(20))\nNOT DETERMINISTIC MODIFIES SQL DATA\nBEGIN\nINSERT INTO source VALUES (id), (NULL);\nEND',0 -TIMESTAMP,HOSTNAME,root,localhost,4,10,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,9,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,8,QUERY,test,'INSERT INTO source VALUES (NULL)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,13,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,12,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,11,QUERY,test,'INSERT INTO source VALUES (NULL)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,16,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,15,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,18,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,17,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,14,QUERY,test,'INSERT INTO source VALUES (NULL), (NULL)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,22,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,21,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,24,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,23,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,20,QUERY,test,'INSERT INTO source VALUES ( NAME_CONST(\'id\',NULL)), (NULL)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,19,QUERY,test,'CALL test_procedure(NULL)',0 -TIMESTAMP,HOSTNAME,root,localhost,4,25,QUERY,test,'DROP PROCEDURE test_procedure',0 -TIMESTAMP,HOSTNAME,root,localhost,4,26,QUERY,test,'DROP TABLE source, dest, dest_2',0 -TIMESTAMP,HOSTNAME,root,localhost,4,27,QUERY,test,'set global server_audit_logging=off',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=on',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'USE test',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'CREATE TABLE source (\nid bigint(20) NOT NULL AUTO_INCREMENT,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'CREATE TABLE dest (\nid bigint(20) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'CREATE TABLE dest_2 (\nid bigint(20) NOT NULL,\nPRIMARY KEY (id)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'CREATE TRIGGER test_trigger\nAFTER INSERT ON source\nFOR EACH ROW\nINSERT INTO dest (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'CREATE TRIGGER test_trigger_2\nAFTER INSERT ON dest\nFOR EACH ROW\nINSERT INTO dest_2 (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'CREATE PROCEDURE test_procedure (IN id bigint(20))\nNOT DETERMINISTIC MODIFIES SQL DATA\nBEGIN\nINSERT INTO source VALUES (id), (NULL);\nEND',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO source VALUES (NULL)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO source VALUES (NULL)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO source VALUES (NULL), (NULL)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest_2 (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO dest (id) VALUES(NEW.id)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'INSERT INTO source VALUES ( NAME_CONST(\'id\',NULL)), (NULL)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'CALL test_procedure(NULL)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'DROP PROCEDURE test_procedure',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'DROP TABLE source, dest, dest_2',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=off',0 diff --git a/mysql-test/suite/plugins/r/server_audit_timestamp.result b/mysql-test/suite/plugins/r/server_audit_timestamp.result new file mode 100644 index 0000000000000..8b6ca58c7a933 --- /dev/null +++ b/mysql-test/suite/plugins/r/server_audit_timestamp.result @@ -0,0 +1,56 @@ +set global server_audit_logging=on; +select 1; +1 +1 +set global server_audit_timestamp_format='CUSTOM-DATE %Y-%m-%d'; +select 2; +2 +2 +set global server_audit_timestamp_format='CUSTOM-TZ %H:%i:%s %z'; +select 3; +3 +3 +set global server_audit_timestamp_format='%Y%m%d %H:%i:%s'; +select 4; +4 +4 +# +# Error handling for long timestamp format +# +set global server_audit_timestamp_format='%H:%i:%s'; +show variables like 'server_audit_timestamp_format'; +Variable_name Value +server_audit_timestamp_format %H:%i:%s +# Attempting to set an excessively long format string. +set global server_audit_timestamp_format='AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'; +ERROR 42000: Variable 'server_audit_timestamp_format' can't be set to the value of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +# Value should still be the old one +show variables like 'server_audit_timestamp_format'; +Variable_name Value +server_audit_timestamp_format %H:%i:%s +# +# Test large expansion (many %B specifiers) +# +set global server_audit_timestamp_format='%M %M %M %M %M %M %M %M %M %M %M %M %M %M %M'; +select 5; +5 +5 +set global server_audit_timestamp_format='%Y%m%d %H:%i:%s'; +set global server_audit_logging=off; +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=on',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 1',0 +CUSTOM-DATE TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_timestamp_format=\'CUSTOM-DATE %Y-%m-%d\'',0 +CUSTOM-DATE TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 2',0 +CUSTOM-TZ TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_timestamp_format=\'CUSTOM-TZ %H:%i:%s %z\'',0 +CUSTOM-TZ TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 3',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_timestamp_format=\'%Y%m%d %H:%i:%s\'',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 4',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_timestamp_format=\'%H:%i:%s\'',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show variables like \'server_audit_timestamp_format\'',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select repeat(\'A\', 130)',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_timestamp_format=\'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\'',1231 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show variables like \'server_audit_timestamp_format\'',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_timestamp_format=\'%M %M %M %M %M %M %M %M %M %M %M %M %M %M %M\'',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select 5',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_timestamp_format=\'%Y%m%d %H:%i:%s\'',0 +TIMESTAMP,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=off',0 diff --git a/mysql-test/suite/plugins/r/thread_pool_server_audit.result b/mysql-test/suite/plugins/r/thread_pool_server_audit.result index 3b6d7d870010a..3ca59d0f5870d 100644 --- a/mysql-test/suite/plugins/r/thread_pool_server_audit.result +++ b/mysql-test/suite/plugins/r/thread_pool_server_audit.result @@ -18,6 +18,7 @@ server_audit_syslog_facility LOG_USER server_audit_syslog_ident mysql-server_auditing server_audit_syslog_info server_audit_syslog_priority LOG_INFO +server_audit_timestamp_format %Y%m%d %H:%i:%s set global server_audit_file_path=null; set global server_audit_incl_users=null; set global server_audit_file_path='server_audit.log'; @@ -89,6 +90,7 @@ server_audit_syslog_facility LOG_USER server_audit_syslog_ident mysql-server_auditing server_audit_syslog_info server_audit_syslog_priority LOG_INFO +server_audit_timestamp_format %Y%m%d %H:%i:%s set global server_audit_mode=1; set global server_audit_events=''; create database sa_db; @@ -242,6 +244,7 @@ server_audit_syslog_facility LOG_USER server_audit_syslog_ident mysql-server_auditing server_audit_syslog_info server_audit_syslog_priority LOG_INFO +server_audit_timestamp_format %Y%m%d %H:%i:%s uninstall plugin server_audit; Warnings: Warning 1620 Plugin is busy and will be uninstalled on shutdown diff --git a/mysql-test/suite/plugins/t/server_audit_query_id.test b/mysql-test/suite/plugins/t/server_audit_query_id.test index 950f0a42c0eab..b1b8488db9e62 100644 --- a/mysql-test/suite/plugins/t/server_audit_query_id.test +++ b/mysql-test/suite/plugins/t/server_audit_query_id.test @@ -83,7 +83,7 @@ set global server_audit_logging=off; --exec perl $MYSQL_TEST_DIR/suite/plugins/t/normalize_query_id.pl $SEARCH_FILE # Output the log without heavy replacements so we can see the actual order ---replace_regex /\d\d\d\d\d\d\d\d \d\d:\d\d:\d\d/TIMESTAMP/ /,[^,]+,root,(localhost|localhost:[0-9]+),/,HOSTNAME,root,localhost,/ +--replace_regex /\d\d\d\d\d\d\d\d \d\d:\d\d:\d\d/TIMESTAMP/ /,[^,]+,root,(localhost|localhost:[0-9]+),\d+,\d+,/,HOSTNAME,root,localhost,ID,ID,/ cat_file $SEARCH_FILE; remove_file $SEARCH_FILE; diff --git a/mysql-test/suite/plugins/t/server_audit_timestamp.opt b/mysql-test/suite/plugins/t/server_audit_timestamp.opt new file mode 100644 index 0000000000000..f42cc19b15a0e --- /dev/null +++ b/mysql-test/suite/plugins/t/server_audit_timestamp.opt @@ -0,0 +1,4 @@ +--plugin-load-add=server_audit +--server_audit_file_path='server_audit_timestamp.log' +--server_audit_output_type=file +--server_audit_events='query' diff --git a/mysql-test/suite/plugins/t/server_audit_timestamp.test b/mysql-test/suite/plugins/t/server_audit_timestamp.test new file mode 100644 index 0000000000000..2be866d7a2312 --- /dev/null +++ b/mysql-test/suite/plugins/t/server_audit_timestamp.test @@ -0,0 +1,58 @@ +--source include/not_embedded.inc + +if (!$SERVER_AUDIT_SO) { + skip No SERVER_AUDIT plugin; +} + +--disable_ps_protocol +--disable_view_protocol + +# The plugin is loaded via .opt file +let $MYSQLD_DATADIR= `SELECT @@datadir`; +let SEARCH_FILE= $MYSQLD_DATADIR/server_audit_timestamp.log; + +set global server_audit_logging=on; + +# Default format +select 1; + +# Custom format 1: Just date +set global server_audit_timestamp_format='CUSTOM-DATE %Y-%m-%d'; +select 2; + +# Custom format 2: Including timezone (if supported by system strftime) +set global server_audit_timestamp_format='CUSTOM-TZ %H:%i:%s %z'; +select 3; + +# Revert to default +set global server_audit_timestamp_format='%Y%m%d %H:%i:%s'; +select 4; + +--echo # +--echo # Error handling for long timestamp format +--echo # +set global server_audit_timestamp_format='%H:%i:%s'; +show variables like 'server_audit_timestamp_format'; + +--echo # Attempting to set an excessively long format string. +let $long_format= `select repeat('A', 130)`; +--error ER_WRONG_VALUE_FOR_VAR +eval set global server_audit_timestamp_format='$long_format'; + +--echo # Value should still be the old one +show variables like 'server_audit_timestamp_format'; + +--echo # +--echo # Test large expansion (many %B specifiers) +--echo # +set global server_audit_timestamp_format='%M %M %M %M %M %M %M %M %M %M %M %M %M %M %M'; +select 5; +set global server_audit_timestamp_format='%Y%m%d %H:%i:%s'; + +set global server_audit_logging=off; + +# We use replace_regex to mask the actual volatile parts but keep our prefixes +--replace_regex /\d{4}\d{2}\d{2} \d{2}:\d{2}:\d{2}/TIMESTAMP/ /CUSTOM-DATE \d{4}-\d{2}-\d{2}/CUSTOM-DATE TIMESTAMP/ /CUSTOM-TZ \d{2}:\d{2}:\d{2} [+-]\d{4}/CUSTOM-TZ TIMESTAMP/ /CUSTOM-TZ \d{2}:\d{2}:\d{2}/CUSTOM-TZ TIMESTAMP/ /([A-Z][a-z]+ ){10,}[A-Z][a-z]+/TIMESTAMP/ /\d{2}:\d{2}:\d{2}/TIMESTAMP/ /,[^,]+,root,(localhost|localhost:[0-9]+),(\d+),(\d+),/,HOSTNAME,root,localhost,ID,ID,/ +cat_file $SEARCH_FILE; + +remove_file $SEARCH_FILE; diff --git a/plugin/server_audit/server_audit.cc b/plugin/server_audit/server_audit.cc index 0fc83872f62e2..2138ad5306295 100644 --- a/plugin/server_audit/server_audit.cc +++ b/plugin/server_audit/server_audit.cc @@ -90,6 +90,18 @@ static void closelog() {} #ifndef USERNAME_CHAR_LENGTH #define USERNAME_CHAR_LENGTH 128 #endif +#ifndef TIMESTAMP_FORMAT_LENGTH +#define TIMESTAMP_FORMAT_LENGTH 128 +#endif +#ifndef TIMESTAMP_OUTPUT_LENGTH +#define TIMESTAMP_OUTPUT_LENGTH 256 +#endif +#ifndef MAX_AUDIT_PAYLOAD_LENGTH +#define MAX_AUDIT_PAYLOAD_LENGTH 1024 +#endif +#ifndef MAX_AUDIT_QUERY_LENGTH +#define MAX_AUDIT_QUERY_LENGTH 2048 +#endif #ifndef DBUG_OFF #define PLUGIN_DEBUG_VERSION "-debug" @@ -103,8 +115,9 @@ static void closelog() {} const char *(*thd_priv_host_ptr)(MYSQL_THD thd, size_t *length); static char *incl_users, *excl_users, - *file_path, *syslog_info; + *file_path, *syslog_info, *timestamp_format; static char path_buffer[FN_REFLEN]; +static char timestamp_format_buffer[TIMESTAMP_FORMAT_LENGTH]; static unsigned int mode; static ulong output_type; static ulong syslog_facility, syslog_priority; @@ -191,6 +204,10 @@ static void update_syslog_ident(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); static void rotate_log(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); +static int check_timestamp_format(MYSQL_THD thd, struct st_mysql_sys_var *var, + void *save, struct st_mysql_value *value); +static void update_timestamp_format(MYSQL_THD thd, struct st_mysql_sys_var *var, + void *var_ptr, const void *save); static void sync_log(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); @@ -269,6 +286,11 @@ static MYSQL_SYSVAR_STR(syslog_info, syslog_info, static MYSQL_SYSVAR_UINT(query_log_limit, query_log_limit, PLUGIN_VAR_OPCMDARG, "Limit on the length of the query string in a record", NULL, NULL, 1024, 0, 0x7FFFFFFF, 1); +static MYSQL_SYSVAR_STR(timestamp_format, timestamp_format, + PLUGIN_VAR_RQCMDARG, + "A format string used to print the timestamp into the audit log messages " + "The format used is the same as DATE_FORMAT", + check_timestamp_format, update_timestamp_format, "%Y%m%d %H:%i:%s"); char locinfo_ini_value[sizeof(struct connection_info)+4]; @@ -353,6 +375,7 @@ static struct st_mysql_sys_var* vars[] = { MYSQL_SYSVAR(syslog_facility), MYSQL_SYSVAR(syslog_priority), MYSQL_SYSVAR(query_log_limit), + MYSQL_SYSVAR(timestamp_format), MYSQL_SYSVAR(loc_info), NULL }; @@ -1087,7 +1110,7 @@ static void change_connection(struct connection_info *cn, Write to the log */ -static int write_log(const char *message, size_t len) +static int write_log(const char *message, size_t len, time_t ts) { #if defined _WIN32 || !defined SUX_LOCK_GENERIC DBUG_ASSERT(lock_operations.is_locked_or_waiting()); @@ -1098,7 +1121,23 @@ static int write_log(const char *message, size_t len) { if (logfile) { - if (!(is_active= (logger_write(logfile, message, len) == (int) len))) + MYSQL_TIME ltime; + thd_gmt_sec_to_TIME(NULL, <ime, ts); + + size_t ts_len= 0; + char *ts_start= (char *) message - TIMESTAMP_OUTPUT_LENGTH; + + thd_TIME_to_str(NULL, <ime, timestamp_format_buffer, + ts_start, TIMESTAMP_OUTPUT_LENGTH); + ts_len= strlen(ts_start); + + if (ts_len > 0 && ts_len < TIMESTAMP_OUTPUT_LENGTH) + memmove((char *) message - ts_len, ts_start, ts_len); + + char *final_message= (char *) message - ts_len; + size_t final_len= len + ts_len; + + if (!(is_active= (logger_write(logfile, final_message, final_len) == (int) final_len))) { ++log_write_failures; result= 1; @@ -1107,9 +1146,10 @@ static int write_log(const char *message, size_t len) } else if (output_type == OUTPUT_SYSLOG) { + /* Syslog doesn't need the audit timestamp. Skip the leading comma. */ syslog(syslog_facility_codes[syslog_facility] | syslog_priority_codes[syslog_priority], - "%s %.*s", syslog_info, (int) len, message); + "%s %.*s", syslog_info, (int) len - 1, message + 1); } return result; @@ -1119,10 +1159,10 @@ static int write_log(const char *message, size_t len) Write to the log, acquiring the lock. */ -static int write_log_and_lock(const char *message, size_t len) +static int write_log_and_lock(const char *message, size_t len, time_t ts) { lock_operations.rd_lock(); - int result= write_log(message, len); + int result= write_log(message, len, ts); lock_operations.rd_unlock(); return result; } @@ -1132,18 +1172,17 @@ static int write_log_and_lock(const char *message, size_t len) Write to the log @param lock whether the caller did not acquire lock_operations -*/ -static int write_log_maybe_lock(const char *message, size_t len, bool lock) + */ +static int write_log_maybe_lock(const char *message, size_t len, bool lock, time_t ts) { if (unlikely(!lock)) - return write_log(message, len); + return write_log(message, len, ts); else - return write_log_and_lock(message, len); + return write_log_and_lock(message, len, ts); } static size_t log_header(char *message, size_t message_len, - time_t *ts, const char *serverhost, size_t serverhost_len, const char *username, unsigned int username_len, const char *host, unsigned int host_len, @@ -1151,7 +1190,6 @@ static size_t log_header(char *message, size_t message_len, unsigned int connection_id, unsigned int port, long long query_id, const char *operation) { - struct tm tm_time; char port_str[16]; if (host_len == 0 && userip_len != 0) { @@ -1168,25 +1206,14 @@ static size_t log_header(char *message, size_t message_len, That was added to find the possible cause of the MENT-1438. Supposed to be removed after that. */ - if (username_len > 1024) + if (username_len > MAX_AUDIT_PAYLOAD_LENGTH) { username= "unknown_user"; username_len= (unsigned int) strlen(username); } - if (output_type == OUTPUT_SYSLOG) - return my_snprintf(message, message_len, - "%.*s,%.*s,%.*s%s,%d,%lld,%s", - (int) serverhost_len, serverhost, - username_len, username, - host_len, host, port_str, - connection_id, query_id, operation); - - (void) localtime_r(ts, &tm_time); return my_snprintf(message, message_len, - "%04d%02d%02d %02d:%02d:%02d,%.*s,%.*s,%.*s%s,%d,%lld,%s", - tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday, - tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, + ",%.*s,%.*s,%.*s%s,%d,%lld,%s", (int) serverhost_len, serverhost, username_len, username, host_len, host, port_str, @@ -1211,23 +1238,24 @@ static int log_proxy(const struct connection_info *cn, { time_t ctime; size_t csize; - char message[1024]; + char raw_message[MAX_AUDIT_PAYLOAD_LENGTH + TIMESTAMP_OUTPUT_LENGTH]; + char *message= raw_message + TIMESTAMP_OUTPUT_LENGTH; (void) time(&ctime); - csize= log_header(message, sizeof(message)-1, &ctime, + csize= log_header(message, MAX_AUDIT_PAYLOAD_LENGTH - 1, servhost, servhost_len, cn->user, cn->user_length, cn->host, cn->host_length, cn->ip, cn->ip_length, event->thread_id, event->port, 0, "PROXY_CONNECT"); - csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, + csize+= my_snprintf(message+csize, MAX_AUDIT_PAYLOAD_LENGTH - 1 - csize, ",%.*s,`%.*s`@`%.*s`,%d", cn->db_length, cn->db, cn->proxy_length, cn->proxy, cn->proxy_host_length, cn->proxy_host, event->status); message[csize]= '\n'; - return write_log_and_lock(message, csize + 1); + return write_log_and_lock(message, csize + 1, ctime); } @@ -1237,12 +1265,13 @@ static int log_connection(const struct connection_info *cn, { time_t ctime; size_t csize; - char message[1024]; + char raw_message[MAX_AUDIT_PAYLOAD_LENGTH + TIMESTAMP_OUTPUT_LENGTH]; + char *message= raw_message + TIMESTAMP_OUTPUT_LENGTH; char tls_obj[32]; size_t obj_len; (void) time(&ctime); - csize= log_header(message, sizeof(message)-1, &ctime, + csize= log_header(message, MAX_AUDIT_PAYLOAD_LENGTH - 1, servhost, servhost_len, cn->user, cn->user_length, cn->host, cn->host_length, @@ -1250,11 +1279,11 @@ static int log_connection(const struct connection_info *cn, event->thread_id, event->port, 0, type); obj_len= create_tls_obj(event, tls_obj, sizeof(tls_obj)); - csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, + csize+= my_snprintf(message+csize, MAX_AUDIT_PAYLOAD_LENGTH - 1 - csize, ",%.*s,%.*s,%d", cn->db_length, cn->db, (int) obj_len, tls_obj, event->status); message[csize]= '\n'; - return write_log_and_lock(message, csize + 1); + return write_log_and_lock(message, csize + 1, ctime); } @@ -1263,23 +1292,24 @@ static int log_connection_event(const struct mysql_event_connection *event, { time_t ctime; size_t csize; - char message[1024]; + char raw_message[MAX_AUDIT_PAYLOAD_LENGTH + TIMESTAMP_OUTPUT_LENGTH]; + char *message= raw_message + TIMESTAMP_OUTPUT_LENGTH; char tls_obj[32]; size_t obj_len; (void) time(&ctime); - csize= log_header(message, sizeof(message)-1, &ctime, + csize= log_header(message, MAX_AUDIT_PAYLOAD_LENGTH - 1, servhost, servhost_len, event->user, event->user_length, event->host, event->host_length, event->ip, event->ip_length, event->thread_id, event->port, 0, type); obj_len= create_tls_obj(event, tls_obj, sizeof(tls_obj)); - csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, + csize+= my_snprintf(message+csize, MAX_AUDIT_PAYLOAD_LENGTH - 1 - csize, ",%.*s,%.*s,%d", (int) event->database.length,event->database.str, (int) obj_len, tls_obj, event->status); message[csize]= '\n'; - return write_log_and_lock(message, csize + 1); + return write_log_and_lock(message, csize + 1, ctime); } @@ -1481,9 +1511,9 @@ static int log_statement_ex(struct connection_info *cn, int error_code, const char *type, int take_lock) { size_t csize; - char message_loc[2048]; - char *message= message_loc; - size_t message_size= sizeof(message_loc); + char raw_message_loc[MAX_AUDIT_QUERY_LENGTH + TIMESTAMP_OUTPUT_LENGTH]; + char *message= raw_message_loc + TIMESTAMP_OUTPUT_LENGTH; + size_t message_size= MAX_AUDIT_QUERY_LENGTH; char *uh_buffer; size_t uh_buffer_size; const char *db; @@ -1522,7 +1552,7 @@ static int log_statement_ex(struct connection_info *cn, return 0; } - csize= log_header(message, message_size-1, &ev_time, + csize= log_header(message, message_size-1, servhost, servhost_len, cn->user, cn->user_length,cn->host, cn->host_length, cn->ip, cn->ip_length, thd_id, cn->port, query_id, type); @@ -1535,13 +1565,14 @@ static int log_statement_ex(struct connection_info *cn, if (query_len > (message_size - csize)/2) { - size_t big_buffer_alloced= (query_len * 2 + csize + 4095) & ~4095L; + size_t big_buffer_alloced= (query_len * 2 + csize + 4095 + TIMESTAMP_OUTPUT_LENGTH) & ~4095L; if (!(big_buffer= static_cast(malloc(big_buffer_alloced)))) return 0; - memcpy(big_buffer, message, csize); - message= big_buffer; - message_size= big_buffer_alloced; + char *new_message= big_buffer + TIMESTAMP_OUTPUT_LENGTH; + memcpy(new_message, message, csize); + message= new_message; + message_size= big_buffer_alloced - TIMESTAMP_OUTPUT_LENGTH; } uh_buffer= message + csize; @@ -1586,7 +1617,7 @@ static int log_statement_ex(struct connection_info *cn, csize+= my_snprintf(message+csize, message_size - 1 - csize, "\',%d", error_code); message[csize]= '\n'; - result= write_log_maybe_lock(message, csize + 1, take_lock); + result= write_log_maybe_lock(message, csize + 1, take_lock, ev_time); if (cn->sync_statement && output_type == OUTPUT_FILE && logfile) { @@ -1626,21 +1657,22 @@ static int log_table(const struct connection_info *cn, const struct mysql_event_table *event, const char *type) { size_t csize; - char message[1024]; + char raw_message[MAX_AUDIT_PAYLOAD_LENGTH + TIMESTAMP_OUTPUT_LENGTH]; + char *message = raw_message + TIMESTAMP_OUTPUT_LENGTH; time_t ctime; (void) time(&ctime); - csize= log_header(message, sizeof(message)-1, &ctime, + csize= log_header(message, MAX_AUDIT_PAYLOAD_LENGTH - 1, servhost, servhost_len, event->user, SAFE_STRLEN_UI(event->user), event->host, SAFE_STRLEN_UI(event->host), event->ip, SAFE_STRLEN_UI(event->ip), event->thread_id, event->port, cn->query_id, type); - csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, ",%.*s,%.*s,", + csize+= my_snprintf(message+csize, MAX_AUDIT_PAYLOAD_LENGTH - 1 - csize, ",%.*s,%.*s,", (int) event->database.length, event->database.str, (int) event->table.length, event->table.str); message[csize]= '\n'; - return write_log_and_lock(message, csize + 1); + return write_log_and_lock(message, csize + 1, ctime); } @@ -1648,25 +1680,26 @@ static int log_rename(const struct connection_info *cn, const struct mysql_event_table *event) { size_t csize; - char message[1024]; + char raw_message[MAX_AUDIT_PAYLOAD_LENGTH + TIMESTAMP_OUTPUT_LENGTH]; + char *message= raw_message + TIMESTAMP_OUTPUT_LENGTH; time_t ctime; (void) time(&ctime); - csize= log_header(message, sizeof(message)-1, &ctime, + csize= log_header(message, MAX_AUDIT_PAYLOAD_LENGTH - 1, servhost, servhost_len, event->user, SAFE_STRLEN_UI(event->user), event->host, SAFE_STRLEN_UI(event->host), event->ip, SAFE_STRLEN_UI(event->ip), event->thread_id, event->port, cn->query_id, "RENAME"); - csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize, + csize+= my_snprintf(message+csize, MAX_AUDIT_PAYLOAD_LENGTH - 1 - csize, ",%.*s,%.*s|%.*s.%.*s,", (int) event->database.length, event->database.str, (int) event->table.length, event->table.str, (int) event->new_database.length, event->new_database.str, (int) event->new_table.length, event->new_table.str); message[csize]= '\n'; - return write_log_and_lock(message, csize + 1); + return write_log_and_lock(message, csize + 1, ctime); } @@ -2111,6 +2144,11 @@ static int server_audit_init(void*) { update_excl_users(NULL, NULL, NULL, &excl_users); } + if (timestamp_format && timestamp_format[0]) + { + update_timestamp_format(NULL, NULL, NULL, ×tamp_format); + } + error_header(); fprintf(stderr, "MariaDB Audit Plugin version %s%s STARTED.\n", @@ -2300,6 +2338,40 @@ static void update_file_path(MYSQL_THD thd, st_mysql_sys_var *, void *, } +static int check_timestamp_format(MYSQL_THD thd, st_mysql_sys_var *, + void *save, struct st_mysql_value *value) +{ + const char *format; + int len= 0; + + format= value->val_str(value, NULL, &len); + if ((size_t) len >= TIMESTAMP_FORMAT_LENGTH) + { + error_header(); + fprintf(stderr, "server_audit_timestamp_format can't exceed %d characters.\n", + TIMESTAMP_FORMAT_LENGTH - 1); + return 1; + } + *((const char **) save)= format; + return 0; +} + + +static void update_timestamp_format(MYSQL_THD thd, st_mysql_sys_var *, void *, + const void *save) +{ + char *new_val= *static_cast(save); + if (!new_val) + new_val= empty_str; + + lock_operations.wr_lock(); + strncpy(timestamp_format_buffer, new_val, sizeof(timestamp_format_buffer)-1); + timestamp_format_buffer[sizeof(timestamp_format_buffer)-1]= 0; + timestamp_format= timestamp_format_buffer; + lock_operations.wr_unlock(); +} + + static void update_file_rotations(MYSQL_THD, st_mysql_sys_var *, void *, const void *save) { diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 0d2fe376a79a4..e56a0273574e1 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -48,7 +48,6 @@ // calc_time_from_sec, // get_date_time_format_str #include "tztime.h" // struct Time_zone -#include "sql_class.h" // THD #include #include @@ -1400,6 +1399,36 @@ static bool get_interval_info(const char *str, size_t length,CHARSET_INFO *cs, return (str != end); } +extern "C" +void thd_TIME_to_str(MYSQL_THD thd, const MYSQL_TIME *ltime, const char *format, + char *buf, unsigned int buf_len) +{ + String str(buf, buf_len, system_charset_info); + String fmt(format, strlen(format), system_charset_info); + /* + The String(char*, ...) constructor sets both the allocated capacity and the + current string length to buf_len. We must reset the current length to 0 to + allow make_date_time to append from the beginning without triggering a + heap reallocation. + */ + str.length(0); + make_date_time(thd ? thd : current_thd, &fmt, ltime, MYSQL_TIMESTAMP_DATETIME, + thd ? thd->variables.lc_time_names : + global_system_variables.lc_time_names, + &str); + /* + If the formatted string fits in buf_len, c_ptr_safe() returns buf and no + copying is needed. If it exceeded buf_len, a heap allocation occurred, + and we must copy the result(partially) back to the caller's buffer. + */ + if (unlikely(str.c_ptr_safe() != buf)) + { + unsigned int len= MY_MIN(str.length(), buf_len - 1); + memcpy(buf, str.ptr(), len); + buf[len]= 0; + } +} + longlong Item_func_period_add::val_int() { diff --git a/sql/sql_plugin_services.inl b/sql/sql_plugin_services.inl index ff43bcb2ff331..7ef6f0a7efba8 100644 --- a/sql/sql_plugin_services.inl +++ b/sql/sql_plugin_services.inl @@ -59,7 +59,8 @@ static struct kill_statement_service_st thd_kill_statement_handler= { static struct thd_timezone_service_st thd_timezone_handler= { thd_TIME_to_gmt_sec, - thd_gmt_sec_to_TIME + thd_gmt_sec_to_TIME, + thd_TIME_to_str }; static struct my_sha2_service_st my_sha2_handler = {