File ddl_log.c¶
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* ddl_log.c -
*/
#ident "$Id$"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#if defined(WINDOWS)
#include <sys/timeb.h>
#include <process.h>
#include <io.h>
#else
#include <unistd.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <signal.h>
#endif
#include <assert.h>
#include "porting.h"
#include "cas_common.h"
#include "ddl_log.h"
#include "parse_tree.h"
#include "system_parameter.h"
#include "environment_variable.h"
#include "broker_config.h"
#include "util_func.h"
#include "hide_password.h"
#include "db.h"
#define DDL_LOG_MSG (256)
#define DDL_LOG_PATH "log/ddl_audit"
#define DDL_LOG_LOADDB_FILE_PATH "log/ddl_audit/loaddb"
#define DDL_LOG_CSQL_FILE_PATH "log/ddl_audit/csql"
#define FILE_BUFFER_SIZE (1024)
#define TIME_STRING_SIZE (16)
#define DDL_TIME_LEN (22)
#define DDL_ELAPSED_TIME_LEN (36) // DDL_TIME_LEN + "elapsed time "
#define SQL_TEXT_SIZE (2048)
#define SQL_TEXT_SIZE_MAX (8192)
#define SQL_TEXT_INCR (1024)
typedef struct t_ddl_audit_handle T_DDL_AUDIT_HANDLE;
struct t_ddl_audit_handle
{
char *sql_text;
int sql_text_len; // Not include null terminated character
int alloc_size; // Allocated size of sql_text
char zsql_text[SQL_TEXT_SIZE];
#ifdef _USE_ERR_MSG_IN_LOGDDL_
char *err_msg;
#endif
char db_name[DB_MAX_IDENTIFIER_LENGTH];
char user_name[DB_MAX_USER_LENGTH];
T_APP_NAME app_name;
char br_name[BROKER_NAME_LEN];
int br_index;
char ip_addr[16];
int pid;
int ddl_stmt_cnt;
int ddl_stmt_cnt_backup;
char str_qry_exec_begin_time[DDL_TIME_LEN];
struct timeval qry_exec_begin_time;
char elapsed_time[DDL_ELAPSED_TIME_LEN];
int file_line_number;
int err_code;
char msg[DDL_LOG_MSG];
char load_filename[PATH_MAX];
char copy_filename[PATH_MAX];
char copy_fullpath[PATH_MAX];
char execute_type;
T_LOADDB_FILE_TYPE loaddb_file_type;
T_CSQL_INPUT_TYPE csql_input_type;
char log_filepath[PATH_MAX];
int commit_count;
bool auto_commit_mode;
};
static T_DDL_AUDIT_HANDLE ddl_audit_handle;
static bool is_first_initialized = true;
static bool ddl_logging_enabled = false;
static UINT64 ddl_logging_size = 0ULL;
static void logddl_make_filename (char *filename_buf, size_t buf_size, T_APP_NAME app_name);
static int logddl_make_copy_filename (T_APP_NAME app_name, const char *file_full_path, char *copy_filename,
size_t buf_size);
static int logddl_make_copy_dir (T_APP_NAME app_name, char *copy_filename, char *copy_fullpath, size_t buf_size);
static void logddl_backup (const char *path);
#if defined(WINDOWS)
static void unix_style_path (char *path);
#endif /* WINDOWS */
static int logddl_create_dir (const char *new_dir);
static bool logddl_create_log_msg (FILE * fp);
static int logddl_get_current_date_time_string (char *buf, size_t size);
static int logddl_file_copy (char *src_file, char *dest_file);
static bool logddl_file_backup (T_APP_NAME app_name, T_CSQL_INPUT_TYPE csql_input_type);
#ifdef _USE_ERR_MSG_IN_LOGDDL_
static void logddl_remove_char (char *string, char ch);
#endif
static FILE *logddl_open (T_APP_NAME app_name);
static int logddl_get_time_string (char *buf, struct timeval *time_val);
static FILE *logddl_fopen_and_lock (const char *path, const char *mode);
static void logddl_timeval_diff (struct timeval *start, struct timeval *end);
static const char *logddl_get_app_name (T_APP_NAME app_name);
static bool logddl_is_ddl_type (int node_type, PT_NODE * node);
static void logddl_set_sql_text (char *sql_text, int sql_len, HIDE_PWD_INFO_PTR hide_pwd_info_ptr);
static bool logddl_set_stmt_type (int stmt_type, PT_NODE * statement);
static bool is_executed_ddl_for_trans = false;
static bool has_password_type = false;
void
logddl_init (T_APP_NAME app_name)
{
if (!is_first_initialized)
{
ddl_audit_handle.sql_text[0] = '\0';
ddl_audit_handle.sql_text_len = 0;
#ifdef _USE_ERR_MSG_IN_LOGDDL_
FREE_MEM (ddl_audit_handle.err_msg);
#endif
}
memset (&ddl_audit_handle, 0x00, sizeof (T_DDL_AUDIT_HANDLE));
ddl_audit_handle.ddl_stmt_cnt = 0;
ddl_audit_handle.ddl_stmt_cnt_backup = 0;
ddl_audit_handle.execute_type = LOGDDL_RUN_EXECUTE_FUNC;
ddl_audit_handle.loaddb_file_type = LOADDB_FILE_TYPE_NONE;
ddl_audit_handle.csql_input_type = CSQL_INPUT_TYPE_NONE;
ddl_audit_handle.app_name = app_name;
if (is_first_initialized)
{
is_first_initialized = false;
ddl_audit_handle.sql_text = ddl_audit_handle.zsql_text;
ddl_audit_handle.alloc_size = SQL_TEXT_SIZE;
}
}
void
logddl_free (bool all_free)
{
if (is_first_initialized)
{
logddl_init (APP_NAME_NONE);
return;
}
if (ddl_logging_enabled == false)
{
return;
}
if (ddl_audit_handle.alloc_size > SQL_TEXT_SIZE_MAX)
{
FREE_MEM (ddl_audit_handle.sql_text);
ddl_audit_handle.sql_text = ddl_audit_handle.zsql_text;
ddl_audit_handle.alloc_size = SQL_TEXT_SIZE;
}
ddl_audit_handle.sql_text[0] = '\0';
ddl_audit_handle.sql_text_len = 0;
#ifdef _USE_ERR_MSG_IN_LOGDDL_
FREE_MEM (ddl_audit_handle.err_msg);
#endif
ddl_audit_handle.ddl_stmt_cnt = 0;
ddl_audit_handle.ddl_stmt_cnt_backup = 0;
ddl_audit_handle.execute_type = LOGDDL_RUN_EXECUTE_FUNC;
ddl_audit_handle.loaddb_file_type = LOADDB_FILE_TYPE_NONE;
ddl_audit_handle.str_qry_exec_begin_time[0] = '\0';
ddl_audit_handle.elapsed_time[0] = '\0';
ddl_audit_handle.file_line_number = 0;
ddl_audit_handle.err_code = 0;
ddl_audit_handle.msg[0] = '\0';
if (all_free)
{
is_executed_ddl_for_trans = false;
ddl_audit_handle.auto_commit_mode = false;
ddl_audit_handle.csql_input_type = CSQL_INPUT_TYPE_NONE;
ddl_audit_handle.load_filename[0] = '\0';
ddl_audit_handle.copy_filename[0] = '\0';
ddl_audit_handle.copy_fullpath[0] = '\0';
ddl_audit_handle.commit_count = 0;
}
}
void
logddl_destroy ()
{
if (!is_first_initialized)
{
if (ddl_audit_handle.sql_text != ddl_audit_handle.zsql_text)
{
FREE_MEM (ddl_audit_handle.sql_text);
}
#ifdef _USE_ERR_MSG_IN_LOGDDL_
FREE_MEM (ddl_audit_handle.err_msg);
#endif
is_first_initialized = true;
}
}
void
logddl_check_ddl_audit_param ()
{
ddl_logging_enabled = prm_get_bool_value (PRM_ID_DDL_AUDIT_LOG);
if (ddl_logging_enabled)
{
ddl_audit_handle.pid = (int) getpid ();
}
}
void
logddl_set_db_name (const char *db_name)
{
char *pstr = NULL;
int len;
if (ddl_logging_enabled && db_name)
{
pstr = (char *) strchr (db_name, '@');
len = pstr ? (int) (pstr - db_name) : (int) strlen (db_name);
if (len >= (int) sizeof (ddl_audit_handle.db_name))
{
len = sizeof (ddl_audit_handle.db_name) - 1;
}
memcpy (ddl_audit_handle.db_name, db_name, len);
ddl_audit_handle.db_name[len] = '\0';
logddl_make_filename (ddl_audit_handle.log_filepath, PATH_MAX, ddl_audit_handle.app_name);
}
}
void
logddl_set_user_name (const char *user_name)
{
if (ddl_logging_enabled && user_name)
{
snprintf (ddl_audit_handle.user_name, sizeof (ddl_audit_handle.user_name), user_name);
}
}
void
logddl_set_ip (const char *ip_addr)
{
if (ddl_logging_enabled && ip_addr)
{
snprintf (ddl_audit_handle.ip_addr, sizeof (ddl_audit_handle.ip_addr), ip_addr);
}
}
void
logddl_set_broker_info (const int index, const char *br_name)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.br_index = index;
if (br_name)
{
snprintf (ddl_audit_handle.br_name, BROKER_NAME_LEN, br_name);
}
else
{
ddl_audit_handle.br_name[0] = '\0';
}
logddl_make_filename (ddl_audit_handle.log_filepath, PATH_MAX, ddl_audit_handle.app_name);
}
}
static void
logddl_set_sql_text (char *sql_text, int sql_len, HIDE_PWD_INFO_PTR hide_pwd_info_ptr)
{
const static char *delim_str = "; ";
const static int delim_len = 2;
const static int append_pwd_len = strlen (" PASSWORD '****'");
assert (ddl_logging_enabled == true);
if (!sql_text || sql_len <= 0)
{
return;
}
int tlen = ddl_audit_handle.sql_text_len + sql_len + delim_len + append_pwd_len;
if (ddl_audit_handle.alloc_size <= tlen)
{
int new_size = ddl_audit_handle.alloc_size;
char *ptr = NULL;
while (new_size < tlen)
{
new_size += SQL_TEXT_INCR;
}
ptr = (char *) MALLOC (new_size + 1);
if (!ptr)
{ /* It's a failure, but let's copy as much space as we can */
memcpy (ddl_audit_handle.sql_text, sql_text, ddl_audit_handle.alloc_size);
ddl_audit_handle.sql_text[ddl_audit_handle.alloc_size - 5] = ' ';
ddl_audit_handle.sql_text[ddl_audit_handle.alloc_size - 4] = '.';
ddl_audit_handle.sql_text[ddl_audit_handle.alloc_size - 3] = '.';
ddl_audit_handle.sql_text[ddl_audit_handle.alloc_size - 2] = '.';
ddl_audit_handle.sql_text[ddl_audit_handle.alloc_size - 1] = '\0';
ddl_audit_handle.sql_text_len = ddl_audit_handle.alloc_size - 1;
return;
}
if (ddl_audit_handle.sql_text != ddl_audit_handle.zsql_text)
{
if (ddl_audit_handle.sql_text_len > 0)
{
memcpy (ptr, ddl_audit_handle.sql_text, ddl_audit_handle.sql_text_len);
ptr[ddl_audit_handle.sql_text_len] = '\0';
}
FREE_MEM (ddl_audit_handle.sql_text);
}
ddl_audit_handle.sql_text = ptr;
ddl_audit_handle.alloc_size = new_size;
}
if (ddl_audit_handle.sql_text_len > 0)
{
memcpy (ddl_audit_handle.sql_text + ddl_audit_handle.sql_text_len, delim_str, delim_len);
ddl_audit_handle.sql_text_len += delim_len;
}
if (has_password_type == false)
{
memcpy (ddl_audit_handle.sql_text + ddl_audit_handle.sql_text_len, sql_text, sql_len);
ddl_audit_handle.sql_text_len += sql_len;
}
else
{
char chBk = sql_text[sql_len];
sql_text[sql_len] = '\0';
tlen =
password_snprint (ddl_audit_handle.sql_text + ddl_audit_handle.sql_text_len,
(ddl_audit_handle.alloc_size - ddl_audit_handle.sql_text_len), sql_text, hide_pwd_info_ptr);
sql_text[sql_len] = chBk;
ddl_audit_handle.sql_text_len += tlen;
}
ddl_audit_handle.sql_text[ddl_audit_handle.sql_text_len] = '\0';
}
static bool
logddl_set_stmt_type (int stmt_type, PT_NODE * statement)
{
assert (ddl_logging_enabled == true);
if (logddl_is_ddl_type (stmt_type, statement) == true)
{
is_executed_ddl_for_trans = true;
ddl_audit_handle.ddl_stmt_cnt++;
return true;
}
else if (stmt_type == PT_COMMIT_WORK || stmt_type == PT_ROLLBACK_WORK)
{
/* Although commit/rollback is not a DDL statement,
* the history of commit/rollback for the previously performed DDL statement must be left,
* so set it so that the information can be output.
*/
assert (ddl_audit_handle.ddl_stmt_cnt_backup <= ddl_audit_handle.ddl_stmt_cnt);
if (ddl_audit_handle.ddl_stmt_cnt_backup < ddl_audit_handle.ddl_stmt_cnt)
{
ddl_audit_handle.ddl_stmt_cnt_backup = ddl_audit_handle.ddl_stmt_cnt;
return true;
}
}
return false;
}
void
logddl_set_loaddb_file_type (T_LOADDB_FILE_TYPE file_type)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.loaddb_file_type = file_type;
}
}
void
logddl_set_csql_input_type (T_CSQL_INPUT_TYPE input_type)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.csql_input_type = input_type;
}
}
void
logddl_set_load_filename (const char *load_filename)
{
if (ddl_logging_enabled && load_filename)
{
strncpy (ddl_audit_handle.load_filename, load_filename, sizeof (ddl_audit_handle.load_filename) - 1);
ddl_audit_handle.load_filename[sizeof (ddl_audit_handle.load_filename) - 1] = '\0';
}
}
void
logddl_set_file_line (int file_line)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.file_line_number = file_line;
}
}
#ifdef _USE_ERR_MSG_IN_LOGDDL_
void
logddl_set_err_msg (char *msg)
{
if (ddl_logging_enabled && msg)
{
if (ddl_audit_handle.err_msg != NULL)
{
FREE_MEM (ddl_audit_handle.err_msg);
}
ALLOC_COPY_STRLEN (ddl_audit_handle.err_msg, msg);
logddl_remove_char (ddl_audit_handle.err_msg, '\n');
}
}
#endif
void
logddl_set_err_code (int err_code)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.err_code = err_code;
}
}
void
logddl_set_start_time (struct timeval *time_val)
{
if (ddl_logging_enabled)
{
if (time_val == NULL)
{
struct timeval time;
gettimeofday (&time, NULL);
memcpy (&ddl_audit_handle.qry_exec_begin_time, &time, sizeof (struct timeval));
}
else
{
memcpy (&ddl_audit_handle.qry_exec_begin_time, time_val, sizeof (struct timeval));
}
logddl_get_time_string (ddl_audit_handle.str_qry_exec_begin_time, time_val);
}
}
void
logddl_set_msg (const char *fmt, ...)
{
va_list args;
if (ddl_logging_enabled)
{
va_start (args, fmt);
vsnprintf (ddl_audit_handle.msg, DDL_LOG_MSG, fmt, args);
va_end (args);
}
}
void
logddl_set_execute_type (char exe_type)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.execute_type = exe_type;
}
}
void
logddl_set_commit_count (int count)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.commit_count = count;
}
}
void
logddl_set_commit_mode (bool mode)
{
if (ddl_logging_enabled)
{
ddl_audit_handle.auto_commit_mode = mode;
}
}
static bool
logddl_file_backup (T_APP_NAME app_name, T_CSQL_INPUT_TYPE csql_input_type)
{
if ((app_name == APP_NAME_LOADDB) || (app_name == APP_NAME_CSQL && csql_input_type == CSQL_INPUT_TYPE_FILE))
{
if (strlen (ddl_audit_handle.copy_filename) == 0)
{
if (logddl_make_copy_filename
(app_name, ddl_audit_handle.load_filename, ddl_audit_handle.copy_filename, PATH_MAX) < 0)
{
return false;
}
}
if (strlen (ddl_audit_handle.copy_fullpath) == 0)
{
if (logddl_make_copy_dir
(app_name, ddl_audit_handle.copy_filename, ddl_audit_handle.copy_fullpath, PATH_MAX) < 0)
{
return false;
}
}
logddl_file_copy (ddl_audit_handle.load_filename, ddl_audit_handle.copy_fullpath);
}
return true;
}
static int
logddl_file_copy (char *src_file, char *dest_file)
{
char buf[FILE_BUFFER_SIZE] = { 0 };
size_t size;
int retval = 0;
if (src_file == NULL || dest_file == NULL)
{
return -1;
}
if (access (dest_file, F_OK) == 0)
{
return -1;
}
FILE *fsource = fopen (src_file, "r");
if (fsource == NULL)
{
return -1;
}
FILE *fdest = fopen (dest_file, "w");
if (fdest == NULL)
{
if (fsource != NULL)
{
fclose (fsource);
}
return -1;
}
while (retval == 0)
{
size = fread (buf, 1, FILE_BUFFER_SIZE, fsource);
if (size < 1 || size > FILE_BUFFER_SIZE)
{
if (feof (fsource))
{
break;
}
else
{
retval = ferror (fsource);
}
}
else
{
if (fwrite (buf, sizeof (char), size, fdest) != size)
{
retval = ferror (fdest);
break;
}
}
}
if (fsource != NULL)
{
fclose (fsource);
}
if (fdest != NULL)
{
fclose (fdest);
}
return retval;
}
static int
logddl_make_copy_filename (T_APP_NAME app_name, const char *file_full_path, char *copy_filename, size_t buf_size)
{
const char *env_root = NULL;
char time[TIME_STRING_SIZE] = { 0 };
const char *name_tmp = NULL;
int retval = 0;
if (file_full_path == NULL || copy_filename == NULL)
{
return -1;
}
env_root = envvar_root ();
logddl_get_current_date_time_string (time, TIME_STRING_SIZE);
name_tmp = strrchr (file_full_path, PATH_SEPARATOR);
if (name_tmp == NULL)
{
name_tmp = file_full_path;
}
else
{
name_tmp++;
}
retval = snprintf (copy_filename, buf_size, "%s_%s_%d", name_tmp, time, getpid ());
if (retval < 0)
{
assert (false);
copy_filename[0] = '\0';
return retval;
}
return retval;
}
static int
logddl_make_copy_dir (T_APP_NAME app_name, char *copy_filename, char *copy_fullpath, size_t buf_size)
{
const char *env_root = NULL;
int retval = 0;
if (copy_filename == NULL || copy_fullpath == NULL)
{
return -1;
}
env_root = envvar_root ();
if (app_name == APP_NAME_CSQL)
{
retval = snprintf (copy_fullpath, buf_size, "%s/%s/%s", env_root, DDL_LOG_CSQL_FILE_PATH, copy_filename);
}
else if (app_name == APP_NAME_LOADDB)
{
retval = snprintf (copy_fullpath, buf_size, "%s/%s/%s", env_root, DDL_LOG_LOADDB_FILE_PATH, copy_filename);
}
else
{
retval = -1;
}
if (retval < 0)
{
assert (false);
copy_fullpath[0] = '\0';
return retval;
}
retval = logddl_create_dir (copy_fullpath);
return retval;
}
static void
logddl_make_filename (char *filename_buf, size_t buf_size, T_APP_NAME app_name)
{
const char *env_root = NULL;
assert (filename_buf != NULL);
env_root = envvar_root ();
if (app_name == APP_NAME_CAS)
{
snprintf (filename_buf, buf_size, "%s/%s/%s_%d_ddl.log", env_root, DDL_LOG_PATH, ddl_audit_handle.br_name,
(ddl_audit_handle.br_index + 1));
}
else if (app_name == APP_NAME_CSQL || app_name == APP_NAME_LOADDB)
{
snprintf (filename_buf, buf_size, "%s/%s/%s_%s_ddl.log", env_root, DDL_LOG_PATH,
logddl_get_app_name (app_name), ddl_audit_handle.db_name);
}
else
{
filename_buf[0] = '\0';
}
}
static FILE *
logddl_open (T_APP_NAME app_name)
{
if (ddl_audit_handle.log_filepath[0] == '\0')
{
return NULL;
}
if (logddl_create_dir (ddl_audit_handle.log_filepath) < 0)
{
ddl_audit_handle.log_filepath[0] = '\0';
return NULL;
}
/* note: in "a+" mode, output is always appended */
return logddl_fopen_and_lock (ddl_audit_handle.log_filepath, "a+");
}
inline static bool
is_need_write ()
{
if (ddl_audit_handle.app_name == APP_NAME_LOADDB)
{
if (ddl_audit_handle.loaddb_file_type != LOADDB_FILE_TYPE_SCHEMA
&& ddl_audit_handle.loaddb_file_type != LOADDB_FILE_TYPE_INDEX
&& ddl_audit_handle.loaddb_file_type != LOADDB_FILE_TYPE_TRIGGER)
{
return false;
}
return true;
}
return (bool) (ddl_audit_handle.ddl_stmt_cnt > 0);
}
void
logddl_write_end ()
{
if (ddl_logging_enabled == false)
{
return;
}
if (ddl_audit_handle.execute_type == LOGDDL_RUN_EXECUTE_FUNC)
{
logddl_write ();
}
ddl_log_free:
logddl_free (false);
}
void
logddl_write ()
{
FILE *fp = NULL;
char *dbname = NULL;
char *user_name = NULL;
if (ddl_logging_enabled == false)
{
return;
}
if (is_need_write () == false)
{
return;
}
dbname = db_get_database_name ();
if (dbname)
{
logddl_set_db_name (dbname);
}
else
{
logddl_set_db_name ("unknown");
}
user_name = db_get_user_name ();
if (user_name)
{
logddl_set_user_name (user_name);
}
else
{
logddl_set_user_name ("unknown");
}
fp = logddl_open (ddl_audit_handle.app_name);
if (fp != NULL)
{
if (logddl_file_backup (ddl_audit_handle.app_name, ddl_audit_handle.csql_input_type) == false)
{
goto write_error;
}
if (logddl_create_log_msg (fp) == false)
{
goto write_error;
}
if (ddl_logging_size == 0ULL)
{
ddl_logging_size = prm_get_bigint_value (PRM_ID_DDL_AUDIT_LOG_SIZE);
}
if ((UINT64) ftell (fp) > ddl_logging_size)
{
fclose (fp);
logddl_backup (ddl_audit_handle.log_filepath);
fp = NULL;
}
}
write_error:
if (fp != NULL)
{
fclose (fp);
fp = NULL;
}
if (dbname != NULL)
{
db_string_free (dbname);
}
if (user_name != NULL)
{
db_string_free (user_name);
}
}
void
logddl_write_tran_str (const char *fmt, ...)
{
FILE *fp = NULL;
char msg[DDL_LOG_BUFFER_SIZE] = { 0 };
int len = 0;
struct timeval time_val;
va_list args;
char *dbname = NULL;
char *user_name = NULL;
if (ddl_logging_enabled == false)
{
return;
}
if (is_executed_ddl_for_trans == false || ddl_audit_handle.auto_commit_mode == true)
{
goto write_error;
}
dbname = db_get_database_name ();
if (dbname)
{
logddl_set_db_name (dbname);
}
else
{
logddl_set_db_name ("unknown");
}
user_name = db_get_user_name ();
if (user_name)
{
logddl_set_user_name (user_name);
}
else
{
logddl_set_user_name ("unknown");
}
fp = logddl_open (ddl_audit_handle.app_name);
if (fp != NULL)
{
va_start (args, fmt);
vsnprintf (ddl_audit_handle.msg, DDL_LOG_MSG, fmt, args);
va_end (args);
gettimeofday (&time_val, NULL);
logddl_get_time_string (ddl_audit_handle.str_qry_exec_begin_time, &time_val);
if (logddl_file_backup (ddl_audit_handle.app_name, ddl_audit_handle.csql_input_type) == false)
{
goto write_error;
}
if (ddl_audit_handle.app_name == APP_NAME_CAS)
{
len = snprintf (msg, DDL_LOG_BUFFER_SIZE, "%s %s|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.ip_addr, ddl_audit_handle.user_name, ddl_audit_handle.msg);
}
else if (ddl_audit_handle.app_name == APP_NAME_CSQL)
{
if (ddl_audit_handle.csql_input_type == CSQL_INPUT_TYPE_FILE)
{
len = snprintf (msg, DDL_LOG_BUFFER_SIZE, "%s %d|%s|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.pid, ddl_audit_handle.user_name, ddl_audit_handle.msg,
ddl_audit_handle.copy_filename);
}
else
{
len = snprintf (msg, DDL_LOG_BUFFER_SIZE, "%s %d|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.pid, ddl_audit_handle.user_name, ddl_audit_handle.msg);
}
}
else
{
goto write_error;
}
if (len >= DDL_LOG_BUFFER_SIZE)
{
msg[DDL_LOG_BUFFER_SIZE - 2] = '\n';
len = DDL_LOG_BUFFER_SIZE;
}
if (len < 0 || fwrite (msg, sizeof (char), len, fp) != (size_t) len)
{
goto write_error;
}
if (ddl_logging_size == 0ULL)
{
ddl_logging_size = prm_get_bigint_value (PRM_ID_DDL_AUDIT_LOG_SIZE);
}
if ((UINT64) ftell (fp) > ddl_logging_size)
{
fclose (fp);
logddl_backup (ddl_audit_handle.log_filepath);
fp = NULL;
}
}
write_error:
if (fp != NULL)
{
fclose (fp);
fp = NULL;
}
if (dbname != NULL)
{
db_string_free (dbname);
}
if (user_name != NULL)
{
db_string_free (user_name);
}
logddl_free (true);
}
void
logddl_write_end_for_csql_fileinput (const char *fmt, ...)
{
FILE *fp = NULL;
struct timeval time_val;
va_list args;
char *dbname = NULL;
char *user_name = NULL;
if (ddl_logging_enabled == false)
{
return;
}
if (ddl_audit_handle.app_name != APP_NAME_CSQL && ddl_audit_handle.csql_input_type != CSQL_INPUT_TYPE_FILE)
{
return;
}
if (is_executed_ddl_for_trans == false)
{
return;
}
dbname = db_get_database_name ();
if (dbname)
{
logddl_set_db_name (dbname);
}
else
{
logddl_set_db_name ("unknown");
}
user_name = db_get_user_name ();
if (user_name)
{
logddl_set_user_name (user_name);
}
else
{
logddl_set_user_name ("unknown");
}
fp = logddl_open (ddl_audit_handle.app_name);
if (fp != NULL)
{
va_start (args, fmt);
vsnprintf (ddl_audit_handle.msg, DDL_LOG_MSG, fmt, args);
va_end (args);
gettimeofday (&time_val, NULL);
logddl_get_time_string (ddl_audit_handle.str_qry_exec_begin_time, &time_val);
if (logddl_file_backup (APP_NAME_CSQL, CSQL_INPUT_TYPE_FILE) == false)
{
goto write_error;
}
if (logddl_create_log_msg (fp) == false)
{
goto write_error;
}
if (ddl_logging_size == 0ULL)
{
ddl_logging_size = prm_get_bigint_value (PRM_ID_DDL_AUDIT_LOG_SIZE);
}
if ((UINT64) ftell (fp) > ddl_logging_size)
{
fclose (fp);
logddl_backup (ddl_audit_handle.log_filepath);
fp = NULL;
}
}
write_error:
if (fp != NULL)
{
fclose (fp);
fp = NULL;
}
if (dbname != NULL)
{
db_string_free (dbname);
}
if (user_name != NULL)
{
db_string_free (user_name);
}
logddl_free (true);
}
static bool
logddl_create_log_msg (FILE * fp)
{
char result[20] = { 0 };
struct timeval exec_end, log_time;
assert (ddl_logging_enabled == true);
gettimeofday (&exec_end, NULL);
logddl_timeval_diff (&ddl_audit_handle.qry_exec_begin_time, &exec_end);
if (strlen (ddl_audit_handle.str_qry_exec_begin_time) == 0)
{
gettimeofday (&log_time, NULL);
logddl_get_time_string (ddl_audit_handle.str_qry_exec_begin_time, &log_time);
}
if (ddl_audit_handle.app_name == APP_NAME_LOADDB)
{
if (ddl_audit_handle.err_code < 0)
{
snprintf (result, sizeof (result), "ERROR:%d", ddl_audit_handle.err_code);
snprintf (ddl_audit_handle.msg, DDL_LOG_MSG, "Commited count %8d, Error line %d",
ddl_audit_handle.commit_count, ddl_audit_handle.file_line_number);
}
else
{
strcpy (result, "OK");
}
fprintf (fp, "%s %d|%s|%s|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.pid, ddl_audit_handle.user_name, result, ddl_audit_handle.msg,
ddl_audit_handle.copy_filename);
}
else if (ddl_audit_handle.app_name == APP_NAME_CSQL)
{
if (ddl_audit_handle.csql_input_type == CSQL_INPUT_TYPE_FILE)
{
if (ddl_audit_handle.err_code < 0)
{
snprintf (result, sizeof (result), "ERROR:%d", ddl_audit_handle.err_code);
snprintf (ddl_audit_handle.msg, DDL_LOG_MSG, "Error line %d", ddl_audit_handle.file_line_number);
ddl_audit_handle.elapsed_time[0] = '\0';
fprintf (fp, "%s %d|%s|%s|%s|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.pid,
ddl_audit_handle.user_name,
(ddl_audit_handle.auto_commit_mode) ? "autocommit mode on" : "autocommit mode off",
result, ddl_audit_handle.msg, ddl_audit_handle.copy_filename);
}
else
{
strcpy (result, "OK");
fprintf (fp, "%s %d|%s|%s|%s|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.pid,
ddl_audit_handle.user_name,
(ddl_audit_handle.auto_commit_mode) ? "autocommit mode on" : "autocommit mode off",
result, ddl_audit_handle.msg, ddl_audit_handle.copy_filename);
}
}
else
{
if (ddl_audit_handle.err_code < 0)
{
snprintf (result, sizeof (result), "ERROR:%d", ddl_audit_handle.err_code);
ddl_audit_handle.elapsed_time[0] = '\0';
}
else
{
strcpy (result, "OK");
}
fprintf (fp, "%s %d|%s|%s|%s|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.pid,
ddl_audit_handle.user_name, result, ddl_audit_handle.elapsed_time, ddl_audit_handle.msg,
ddl_audit_handle.sql_text);
}
}
else
{
if (ddl_audit_handle.err_code < 0)
{
snprintf (result, sizeof (result), "ERROR:%d", ddl_audit_handle.err_code);
}
else
{
strcpy (result, "OK");
}
if (ddl_audit_handle.execute_type == LOGDDL_RUN_EXECUTE_BATCH_FUNC)
{
snprintf (ddl_audit_handle.elapsed_time, sizeof (ddl_audit_handle.elapsed_time), "elapsed time 0.000");
}
fprintf (fp, "%s %s|%s|%s|%s|%s|%s|%s\n",
ddl_audit_handle.str_qry_exec_begin_time,
ddl_audit_handle.ip_addr,
ddl_audit_handle.db_name,
ddl_audit_handle.user_name, result, ddl_audit_handle.elapsed_time, ddl_audit_handle.msg,
ddl_audit_handle.sql_text);
}
return true;
}
static void
logddl_backup (const char *path)
{
char backup_file[PATH_MAX] = { 0 };
#if !defined(WINDOWS)
sigset_t new_mask, old_mask;
#endif /* !WINDOWS */
if (snprintf (backup_file, PATH_MAX, "%s.bak", path) >= PATH_MAX)
{
assert_release (0);
backup_file[PATH_MAX - 1] = '\0';
}
#if !defined(WINDOWS)
sigfillset (&new_mask);
sigdelset (&new_mask, SIGINT);
sigdelset (&new_mask, SIGQUIT);
sigdelset (&new_mask, SIGTERM);
sigdelset (&new_mask, SIGHUP);
sigdelset (&new_mask, SIGABRT);
if (sigprocmask (SIG_SETMASK, &new_mask, &old_mask) == 0)
{
unlink (backup_file);
rename (path, backup_file);
sigprocmask (SIG_SETMASK, &old_mask, NULL);
}
#else /* !WINDOWS */
unlink (backup_file);
rename (path, backup_file);
#endif
}
static FILE *
logddl_fopen_and_lock (const char *path, const char *mode)
{
#define MAX_RETRY_COUNT 100
int retry_count = 0;
FILE *ddl_log_fp = NULL;
retry:
ddl_log_fp = fopen (path, mode);
if (ddl_log_fp != NULL)
{
if (lockf (fileno (ddl_log_fp), F_TLOCK, 0) < 0)
{
fclose (ddl_log_fp);
if (retry_count < MAX_RETRY_COUNT)
{
SLEEP_MILISEC (0, 10);
retry_count++;
goto retry;
}
ddl_log_fp = NULL;
}
}
return ddl_log_fp;
}
#if defined(WINDOWS)
static void
unix_style_path (char *path)
{
char *p = NULL;
for (p = path; *p; p++)
{
if (*p == '\\')
*p = '/';
}
}
#endif /* WINDOWS */
static int
logddl_create_dir (const char *new_dir)
{
char *p, path[PATH_MAX] = { 0 };
if (new_dir == NULL)
return -1;
strcpy (path, new_dir);
trim (path);
#if defined(WINDOWS)
unix_style_path (path);
#else
if (access (dirname (path), F_OK) == 0)
{
return 0;
}
path[(int) strlen (path)] = '/';
#endif /* WINDOWS */
p = path;
#if defined(WINDOWS)
if (path[0] == '/')
p = path + 1;
// cppcheck-suppress arrayIndexOutOfBounds
else if (strlen (path) > 3 && path[2] == '/')
p = path + 3;
#else /* WINDOWS */
if (path[0] == '/')
{
p = path + 1;
}
#endif /* WINDOWS */
while (p != NULL)
{
p = strchr (p, '/');
if (p == NULL)
return 0;
if (p != NULL)
*p = '\0';
if (access (path, F_OK) < 0)
{
if (mkdir (path, 0777) < 0)
{
return -1;
}
}
if (p != NULL)
{
*p = '/';
p++;
}
}
return 0;
}
static int
logddl_get_current_date_time_string (char *buf, size_t size)
{
struct tm at_tm;
int len = 0;
time_t t = time (NULL);
localtime_r (&t, &at_tm);
at_tm.tm_year += 1900;
at_tm.tm_mon += 1;
len =
snprintf (buf, size, "%04d%02d%02d_%02d%02d%02d", at_tm.tm_year, at_tm.tm_mon, at_tm.tm_mday, at_tm.tm_hour,
at_tm.tm_min, at_tm.tm_sec);
if (len >= (int) size)
{
assert_release (0);
buf[size - 1] = '\0';
}
return len;
}
static int
logddl_get_time_string (char *buf, struct timeval *time_val)
{
struct tm tm, *tm_p;
time_t sec;
int millisec;
if (buf == NULL)
{
return 0;
}
if (time_val == NULL)
{
/* current time */
util_get_second_and_ms_since_epoch (&sec, &millisec);
}
else
{
sec = time_val->tv_sec;
millisec = time_val->tv_usec / 1000;
}
tm_p = localtime_r (&sec, &tm);
tm.tm_mon++;
buf[0] = ((tm.tm_year % 100) / 10) + '0';
buf[1] = (tm.tm_year % 10) + '0';
buf[2] = '-';
buf[3] = (tm.tm_mon / 10) + '0';
buf[4] = (tm.tm_mon % 10) + '0';
buf[5] = '-';
buf[6] = (tm.tm_mday / 10) + '0';
buf[7] = (tm.tm_mday % 10) + '0';
buf[8] = ' ';
buf[9] = (tm.tm_hour / 10) + '0';
buf[10] = (tm.tm_hour % 10) + '0';
buf[11] = ':';
buf[12] = (tm.tm_min / 10) + '0';
buf[13] = (tm.tm_min % 10) + '0';
buf[14] = ':';
buf[15] = (tm.tm_sec / 10) + '0';
buf[16] = (tm.tm_sec % 10) + '0';
buf[17] = '.';
buf[20] = (millisec % 10) + '0';
millisec /= 10;
buf[19] = (millisec % 10) + '0';
millisec /= 10;
buf[18] = (millisec % 10) + '0';
buf[21] = '\0';
return 21;
}
#ifdef _USE_ERR_MSG_IN_LOGDDL_
static void
logddl_remove_char (char *string, char ch)
{
for (; *string != '\0'; string++)
{
if (*string == ch)
{
strcpy (string, string + 1);
string--;
}
}
}
#endif
static bool
logddl_is_ddl_type (int node_type, PT_NODE * node)
{
switch (node_type)
{
case PT_ALTER:
case PT_ALTER_INDEX:
case PT_ALTER_SERIAL:
case PT_ALTER_STORED_PROCEDURE:
case PT_ALTER_SYNONYM:
case PT_ALTER_TRIGGER:
case PT_CREATE_ENTITY:
case PT_CREATE_INDEX:
case PT_CREATE_SERIAL:
case PT_CREATE_STORED_PROCEDURE:
case PT_CREATE_SYNONYM:
case PT_CREATE_TRIGGER:
case PT_DROP:
case PT_DROP_INDEX:
case PT_DROP_SERIAL:
case PT_DROP_SERVER:
case PT_DROP_STORED_PROCEDURE:
case PT_DROP_SYNONYM:
case PT_DROP_TRIGGER:
case PT_DROP_USER:
case PT_GRANT:
case PT_RENAME:
case PT_RENAME_SERVER:
case PT_RENAME_SYNONYM:
case PT_REVOKE:
case PT_REMOVE_TRIGGER:
case PT_RENAME_TRIGGER:
case PT_UPDATE_STATS:
case PT_TRUNCATE:
/* TODO: check it */
has_password_type = false;
return true;
case PT_CREATE_SERVER:
case PT_ALTER_SERVER:
case PT_ALTER_USER:
case PT_CREATE_USER:
has_password_type = true;
return true;
case PT_METHOD_CALL:
if (node)
{
PT_METHOD_CALL_INFO *call = &node->info.method_call;
if (call->call_or_expr == PT_IS_CALL_STMT)
{
if ((strcasecmp (call->method_name->info.name.original, "set_password") == 0)
|| (strcasecmp (call->method_name->info.name.original, "login") == 0)
|| (strcasecmp (call->method_name->info.name.original, "add_user") == 0))
{
has_password_type = true;
return true;
}
}
}
break;
default:
break;
}
return false;
}
static void
logddl_timeval_diff (struct timeval *start, struct timeval *end)
{
long sec, msec;
assert (start != NULL && end != NULL);
sec = end->tv_sec - start->tv_sec;
msec = (end->tv_usec / 1000) - (start->tv_usec / 1000);
if (msec < 0)
{
msec += 1000;
sec--;
}
snprintf (ddl_audit_handle.elapsed_time, DDL_ELAPSED_TIME_LEN, "elapsed time %ld.%03ld", sec, msec);
}
static const char *
logddl_get_app_name (T_APP_NAME app_name)
{
switch (app_name)
{
case APP_NAME_CAS:
return "cas";
case APP_NAME_CSQL:
return "csql";
case APP_NAME_LOADDB:
return "loaddb";
default:
return "";
}
}
void
logddl_check_and_set_query_text (PT_NODE * statement, int stmt_type, PARSER_CONTEXT * parser)
{
if (ddl_logging_enabled == false)
{
return;
}
if (statement && logddl_set_stmt_type (stmt_type, statement))
{
logddl_set_file_line (statement->line_number);
if (statement->node_type == PT_EXECUTE_PREPARE)
{
assert (statement->info.execute.query->node_type == PT_VALUE);
assert (statement->info.execute.query->type_enum == PT_TYPE_CHAR);
logddl_set_sql_text ((char *) statement->info.execute.query->info.value.data_value.str->bytes,
statement->info.execute.query->info.value.data_value.str->length, NULL);
if (statement->info.execute.using_list)
{
has_password_type = false;
logddl_set_sql_text (statement->sql_user_text, statement->sql_user_text_len, NULL);
}
}
else if (statement->sql_user_text && statement->sql_user_text_len > 0)
{
if (parser->original_buffer == NULL || parser->original_buffer[0] == '\0')
{
logddl_set_sql_text (statement->sql_user_text, statement->sql_user_text_len, NULL);
}
else
{
HIDE_PWD_INFO t_hide_pwd_info;
HIDE_PWD_INFO_PTR hide_pwd_info_ptr = &parser->hide_pwd_info;
int start = (int) (statement->sql_user_text - parser->original_buffer);
INIT_HIDE_PASSWORD_INFO (&t_hide_pwd_info);
password_remake_offset_for_one_query (&t_hide_pwd_info, hide_pwd_info_ptr, start,
start + statement->sql_user_text_len);
logddl_set_sql_text (statement->sql_user_text, statement->sql_user_text_len, &t_hide_pwd_info);
QUIT_HIDE_PASSWORD_INFO (&t_hide_pwd_info);
}
}
}
}
void
logddl_reset_query_text ()
{
ddl_audit_handle.sql_text[0] = '\0';
ddl_audit_handle.sql_text_len = 0;
ddl_audit_handle.ddl_stmt_cnt = 0;
ddl_audit_handle.ddl_stmt_cnt_backup = 0;
}
// only used in callback_handler::prepare()
void
logddl_set_callback_stmt (int stmt_type, char *sql, int len, int err_code, HIDE_PWD_INFO_PTR hide_pwd_info_ptr)
{
if (ddl_logging_enabled)
{
if (logddl_set_stmt_type (stmt_type, NULL))
{
logddl_set_sql_text (sql, len, hide_pwd_info_ptr);
logddl_set_err_code (err_code);
}
}
}