File csql.c¶
File List > cubrid > src > executables > csql.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.
*
*/
/*
* csql.c : csql main module
*/
#ident "$Id$"
#include "config.h"
#include <stdio.h>
#include <fcntl.h>
#include <limits.h>
#include <assert.h>
#if defined(WINDOWS)
#include <direct.h>
#include <io.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else /* !WINDOWS */
#include <sys/time.h>
#include <sys/errno.h>
#include <signal.h>
#include <wctype.h>
#include <editline/readline.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif /* !WINDOWS */
#include "authenticate.h"
#include "csql.h"
#include "filesys.hpp"
#include "filesys_temp.hpp"
#include "system_parameter.h"
#include "message_catalog.h"
#include "porting.h"
#include "release_string.h"
#include "error_manager.h"
#include "language_support.h"
#include "network.h"
#include "schema_manager.h"
#include "optimizer.h"
#include "environment_variable.h"
#include "tcp.h"
#include "db.h"
#include "parser.h"
#include "utility.h"
#include "tsc_timer.h"
#include "dbtype.h"
#include "jsp_cl.h"
#include "db_session.h"
#include "cas_log.h"
#include "ddl_log.h"
#include "network_histogram.hpp"
#include "host_lookup.h"
#include "network_interface_cl.h"
#include "boot_cl.h"
#if defined(WINDOWS)
#include "file_io.h" /* needed for _wyield() */
#endif /* WINDOWS */
#if defined (SA_MODE)
#include "boot_sr.h"
#include "catalog_class.h"
#endif
#if defined (SUPPRESS_STRLEN_WARNING)
#define strlen(s1) ((int) strlen(s1))
#endif /* defined (SUPPRESS_STRLEN_WARNING) */
#define DB_NAME_LEN MAXLOGNAME
#define FREE_MEM(PTR) \
do { \
if (PTR) { \
free(PTR); \
} \
} while (0)
/* input type specification for csql_execute_statements() */
enum
{
FILE_INPUT = 0, /* FILE stream */
STRING_INPUT = 1, /* null-terminated string */
EDITOR_INPUT = 2 /* command buffer */
};
/* the return value of csql_do_session_cmd() */
enum
{
DO_CMD_SUCCESS = 0,
DO_CMD_FAILURE = 1,
DO_CMD_CONNECT = 2,
DO_CMD_EXIT = 3
};
#define CSQL_SESSION_COMMAND_PREFIX(C) (((C) == ';') || ((C) == '!'))
/* size of input buffer */
#define LINE_BUFFER_SIZE (4000)
#define COLUMN_WIDTH_INFO_LIST_INIT_SIZE 24
#define NOT_FOUND -1
#if defined (ENABLE_UNUSED_FUNCTION)
#if !defined(WINDOWS)
/* current max keyword is 16 + nul char + 3 for expansion */
static int csql_Keyword_num;
static KEYWORD_RECORD *csql_Keyword_list;
#endif /* !WINDOWS */
#endif /* ENABLE_UNUSED_FUNCTION */
int (*csql_text_utf8_to_console) (const char *, const int, char **, int *) = NULL;
int (*csql_text_console_to_utf8) (const char *, const int, char **, int *) = NULL;
int csql_Row_count;
int csql_Num_failures;
char csql_Db_name[512];
/* command editor lines */
int csql_Line_lwm = -1;
/* default environment command names */
char csql_Print_cmd[PATH_MAX] = "lpr";
char csql_Pager_cmd[PATH_MAX] = "more"; /* PAGER does not work on WINDOWS */
#if defined(WINDOWS)
char csql_Editor_cmd[PATH_MAX] = "notepad";
#else
char csql_Editor_cmd[PATH_MAX] = "vi";
#endif
#if defined(WINDOWS)
char csql_Shell_cmd[PATH_MAX] = "command.com";
#else
char csql_Shell_cmd[PATH_MAX] = "csh";
#endif
char csql_Formatter_cmd[PATH_MAX];
/* tty file stream which is used for conversation with users.
* In batch mode, this will be set to "/dev/null"
*/
static FILE *csql_Tty_fp = NULL;
/* scratch area to make a message text to be displayed.
* NOTE: Never put chars more than sizeof(csql_Scratch_text).
*/
char csql_Scratch_text[SCRATCH_TEXT_LEN];
int csql_Error_code = NO_ERROR;
typedef enum
{
CSQL_PROMPT_DEFAULT,
CSQL_PROMPT_USER_DEFINED,
CSQL_PROMPT_USER_DEFINED_INCLUDE_USERNAME
} CSQL_PROMPT_TYPE;
static CSQL_PROMPT_TYPE csql_Prompt_user_defined = CSQL_PROMPT_DEFAULT;
static char csql_Prompt_format[100];
static char csql_Prompt_username[100];
static char csql_Prompt[100];
static char csql_Prompt_offline[101]; // for clear "-Wformat-truncation=" warning
/*
* Handles for the various files
*/
FILE *csql_Input_fp = NULL;
FILE *csql_Output_fp = NULL;
FILE *csql_Error_fp = NULL;
/*
* Global longjmp environment to terminate the csql() interpreter in the
* event of fatal error. This should be used rather than calling
* exit(), primarily for the Windows version of the interpreter.
*
* Set csql_Exit_status to the numeric status code to be returned from
* the csql() function after the longjmp has been performed.
*/
static jmp_buf csql_Exit_env;
static int csql_Exit_status = EXIT_SUCCESS;
/* this is non-zero if there is a dangling connection to a database */
static bool csql_Database_connected = false;
static bool csql_Is_interactive = false;
static bool csql_Is_sigint_caught = false;
static bool csql_Is_echo_on = false;
enum
{ HISTO_OFF, HISTO_ON };
static int csql_Is_histo_on = HISTO_OFF;
static bool csql_Is_time_on = true;
static jmp_buf csql_Jmp_buf;
static CSQL_COLUMN_WIDTH_INFO *csql_column_width_info_list = NULL;
static int csql_column_width_info_list_size = 0;
static int csql_column_width_info_list_index = 0;
static bool csql_Query_trace = false;
#if defined (ENABLE_UNUSED_FUNCTION)
#if !defined(WINDOWS)
static char *csql_keyword_generator (const char *text, int state);
static char **csql_cmd_completion_handler (const char *text, int start, int end);
static void init_readline ();
#endif /* ! WINDOWS */
#endif /* ENABLE_UNUSED_FUNCTION */
static void free_csql_column_width_info_list ();
static int initialize_csql_column_width_info_list ();
static int get_column_name_argument (char **column_name, char **val_str, char *argument);
static void csql_pipe_handler (int sig_no);
static void display_buffer (void);
static void start_csql (CSQL_ARGUMENT * csql_arg);
static void csql_read_file (const char *file_name);
static void csql_write_file (const char *file_name, int append_flag);
static void display_error (DB_SESSION * session, int stmt_start_line_no);
static void free_attr_spec (DB_QUERY_TYPE ** attr_spec);
static void csql_print_database (void);
static void csql_set_sys_param (const char *arg_str);
static void csql_get_sys_param (const char *arg_str);
static void csql_set_plan_dump (const char *arg_str);
static void csql_exit_init (void);
static void csql_exit_cleanup (void);
static void csql_print_buffer (void);
static void csql_change_working_directory (const char *dirname);
static void csql_exit_session (int error, bool exit_flag);
static int csql_execute_statements (const CSQL_ARGUMENT * csql_arg, int type, const void *stream, int line_no);
static char *csql_get_external_command (SESSION_CMD cmd_no);
static int csql_do_session_cmd (char *line_read, CSQL_ARGUMENT * csql_arg);
static void csql_set_trace (const char *arg_str);
static void csql_display_trace (void);
static bool csql_is_auto_commit_requested (const CSQL_ARGUMENT * csql_arg);
static int get_host_ip (unsigned char *ip_addr);
static int csql_connect (char *argument, CSQL_ARGUMENT * csql_arg);
static void csql_set_server_output (CSQL_ARGUMENT * csql_arg, bool server_output);
static void csql_print_server_output (const CSQL_ARGUMENT * csql_arg);
static int csql_execute_query (const char *stmts);
static inline void csql_apply_catalog_rebuild_mode (CSQL_ARGUMENT * csql_arg, int *client_type);
static inline int csql_rebuild_catalog (const CSQL_ARGUMENT * csql_arg);
#if defined (ENABLE_UNUSED_FUNCTION)
#if !defined(WINDOWS)
/*
* for readline keyword completion
*/
/*
* csql_keyword_generator()
* return: char*
* text(in)
* state(in)
*/
static char *
csql_keyword_generator (const char *text, int state)
{
static int list_index, len;
/* If this is a new word to complete, initialize now. This includes saving the length of TEXT for efficiency, and
* initializing the index variable to 0. */
if (!state)
{
list_index = 0;
len = strlen (text);
}
if (len == 0)
{
return ((char *) NULL);
}
if (csql_Keyword_list == NULL)
{
return ((char *) NULL);
}
/* Return the next name which partially matches from the keyword list. */
while (list_index < csql_Keyword_num)
{
if (strncasecmp ((csql_Keyword_list + list_index)->keyword, text, len) == 0)
{
char *ret_str = strdup ((csql_Keyword_list + list_index)->keyword);
list_index++;
return ret_str;
}
list_index++;
}
/* If no keyword matched, then return NULL. */
return ((char *) NULL);
}
/*
* csql_cmd_completion_handler()
* return: char**
* text(in)
* start(in)
* end(in)
*/
static char **
csql_cmd_completion_handler (const char *text, int start, int end)
{
char **matches;
matches = (char **) NULL;
matches = completion_matches (text, csql_keyword_generator);
rl_attempted_completion_over = 1;
return (matches);
}
/*
* init_readline() - initialize libedit module
* return: none
*/
static void
init_readline ()
{
rl_attempted_completion_function = csql_cmd_completion_handler;
}
#endif /* !WINDOWS */
#endif /* ENABLE_UNUSED_FUNCTION */
/*
* free_csql_column_width_info_list() - free csql_column_width_info_list
* return: void
*/
static void
free_csql_column_width_info_list ()
{
int i;
if (csql_column_width_info_list == NULL)
{
csql_column_width_info_list_size = 0;
csql_column_width_info_list_index = 0;
return;
}
for (i = 0; i < csql_column_width_info_list_size; i++)
{
if (csql_column_width_info_list[i].name != NULL)
{
free_and_init (csql_column_width_info_list[i].name);
}
}
if (csql_column_width_info_list != NULL)
{
free_and_init (csql_column_width_info_list);
}
csql_column_width_info_list_size = 0;
csql_column_width_info_list_index = 0;
}
/*
* initialize_csql_column_width_info_list() - initialize csql_column_width_info_list
* return: int
*/
static int
initialize_csql_column_width_info_list ()
{
int i;
csql_column_width_info_list =
(CSQL_COLUMN_WIDTH_INFO *) malloc (sizeof (CSQL_COLUMN_WIDTH_INFO) * COLUMN_WIDTH_INFO_LIST_INIT_SIZE);
if (csql_column_width_info_list == NULL)
{
csql_Error_code = CSQL_ERR_NO_MORE_MEMORY;
return CSQL_FAILURE;
}
csql_column_width_info_list_size = COLUMN_WIDTH_INFO_LIST_INIT_SIZE;
csql_column_width_info_list_index = 0;
for (i = 0; i < csql_column_width_info_list_size; i++)
{
csql_column_width_info_list[i].name = NULL;
csql_column_width_info_list[i].width = 0;
}
return CSQL_SUCCESS;
}
/*
* csql_display_msg() - displays the given msg to output device
* return: none
* string(in)
*/
void
csql_display_msg (const char *string)
{
csql_fputs ("\n", csql_Tty_fp);
csql_fputs_console_conv (string, csql_Tty_fp);
csql_fputs ("\n", csql_Tty_fp);
}
/*
* csql_pipe_handler() generic longjmp'ing signal handler used
* where we need to catch broken pipe.
* return: none
* sig_no(in)
*/
static void
csql_pipe_handler (int sig_no)
{
longjmp (csql_Jmp_buf, 1);
}
/*
* display_buffer() - display command buffer into stdout
* return: none
*/
static void
display_buffer (void)
{
volatile int l = 1;
FILE *pf;
#if !defined(WINDOWS)
void (*csql_pipe_save) (int);
#endif /* !WINDOWS */
#if !defined(WINDOWS)
/* There is no SIGPIPE on WINDOWS */
csql_pipe_save = os_set_signal_handler (SIGPIPE, &csql_pipe_handler);
#endif /* !WINDOWS */
if (setjmp (csql_Jmp_buf) == 0)
{
char *edit_contents, *p;
pf = csql_popen (csql_Pager_cmd, csql_Output_fp);
edit_contents = csql_edit_contents_get ();
putc ('\n', pf);
while (edit_contents != NULL && *edit_contents != '\0')
{
fprintf (pf, "%4d ", l++);
p = strchr (edit_contents, '\n');
if (p)
{
fwrite (edit_contents, 1, p - edit_contents, pf);
edit_contents = p + 1;
}
else
{
fwrite (edit_contents, 1, strlen (edit_contents), pf);
edit_contents = NULL;
}
fprintf (pf, "\n");
}
putc ('\n', pf);
csql_pclose (pf, csql_Output_fp);
}
#if !defined(WINDOWS)
(void) os_set_signal_handler (SIGPIPE, csql_pipe_save);
#endif /* !WINDOWS */
}
/*
* change_prompt () - to change the csql prompt displayed to the user.
* The prompt's appearance is customized using a set of user-defined characters specified in the environment variable CUBRID_CSQL_PROMPT.
*
* return: none
* fmt (in) : the format string containing the user-defined characters, typically sourced from CUBRID_CSQL_PROMPT.
* prompt (out) : the buffer where the newly generated, changed prompt string will be stored.
* prompt_size (in) : the maximum length (size) of the prompt buffer.
*
* Note : user-defined characters (escape sequence)
* - \u or \U : replaced with the user name
* - \d or \D : replaced with the database name
* - \h or \H : replaced with the host name
*/
static void
change_prompt (char *fmt, char *prompt, int prompt_size)
{
char *user_name = NULL;
char *database_name = NULL;
char *host_name = NULL;
char *pos = prompt;
int remain = prompt_size - 3; // for prompt delimeter + space + null character
int len;
if (remain <= 0)
{
return;
}
memset (prompt, 0x00, prompt_size);
for (int i = 0; fmt[i] != '\0' && remain > 0;)
{
if (fmt[i] == '\\' && fmt[i + 1] != '\0' && fmt[i + 1] >= 0)
{
char next = fmt[i + 1];
const char *src = NULL;
if (next == 'u' || next == 'U')
{
src = user_name = db_get_user_name ();
strcpy (csql_Prompt_username, user_name);
csql_Prompt_user_defined = CSQL_PROMPT_USER_DEFINED_INCLUDE_USERNAME;
}
else if (next == 'd' || next == 'D')
{
src = database_name = db_get_database_name ();
}
else if (next == 'h' || next == 'H')
{
src = host_name = db_get_host_connected ();
}
if (src)
{
len = strlen (src);
}
else
{
src = &(fmt[i]);
len = 2;
}
if (len > remain)
{
len = remain;
}
memcpy (pos, src, len);
pos += len;
remain -= len;
i += 2;
}
else
{
*pos++ = fmt[i];
remain--;
i++;
}
}
for (; prompt <= pos && (*pos == '\0' || *pos == ' '); --pos);
if (*pos != '>')
{
memcpy (pos + 1, "> \0", 3);
}
else
{
memcpy (pos + 1, " \0", 2);
}
if (user_name)
{
db_string_free (user_name);
}
if (database_name)
{
db_string_free (database_name);
}
#if !defined (WINDOW)
/* check if the prompt contains multi-byte characters */
for (pos = prompt; *pos != '\0'; pos++)
{
if ((signed char) *pos < 0)
{
char *locale = setlocale (LC_CTYPE, NULL);
INTL_CODESET codeset = lang_charset ();
const char *find1 = NULL, *find2 = NULL;
/* check of DB codeset */
if (codeset == INTL_CODESET_UTF8)
{
find1 = "utf8";
find2 = "utf-8";
}
else if (codeset == INTL_CODESET_KSC5601_EUC)
{
find1 = "euckr";
find2 = "euc-kr";
}
else
{
goto multibyte_warning;
}
/* veify if match LANG and DB codeset */
if (strcasestr (locale, find1) != NULL || strcasestr (locale, find2) != NULL)
{
return;
}
else
{
goto multibyte_warning;
}
}
}
return;
multibyte_warning:
strcpy (prompt, csql_get_message (CSQL_PROMPT));
if ((prompt_size - strlen (prompt)) > 1)
{
strcat (prompt, " ");
}
fprintf (stderr, "Warning: %s\n", csql_get_message (CSQL_E_LANG_TEXT));
return;
#else
return;
#endif
}
/*
* start_csql()
* return: none
* sql_arg(in/out): CSQL_ARGUMENT structure
*
* Note:
* There are four file pointers associated
* stdin - input source
* stdout - output file stream
* stderr - error message file stream
* tty_fp - conversation terminal file stream.
* either NULL or stderr
*
* if -o is given, the output file descriptor is duplicated to STDOU_FILENO.
* Also, if -i is given, -c is given or stdin is not a tty,
* `tty_fp' will be set to NULL. (No conversational messages)
* Otherwise, `tty_fp' will be set to stderr
*
* If `single_line_execution' is true, it attemts to execute as soon as
* it get a line. There is command buffer associated. This is effective
* only when INTERACTIVE mode (stdin is tty).
* If `command' is not NULL, it'll execute the command and exit and
* `-i' option, preceding pipe (if any), `-s' option had no effect.
*/
static void
start_csql (CSQL_ARGUMENT * csql_arg)
{
unsigned char line_buf[LINE_BUFFER_SIZE];
unsigned char utf8_line_buf[INTL_UTF8_MAX_CHAR_SIZE * LINE_BUFFER_SIZE];
char *line_read = NULL;
int line_length;
int line_no;
char *ptr; /* loop pointer */
char *line_read_alloced = NULL;
bool is_first_read_line = true;
bool read_whole_line;
char *prompt;
/* check in string block or comment block or identifier block */
bool is_in_block = false;
logddl_set_commit_mode (csql_is_auto_commit_requested (csql_arg));
if (csql_arg->column_output && csql_arg->line_output)
{
csql_Error_code = CSQL_ERR_INVALID_ARG_COMBINATION;
goto fatal_error;
}
csql_Output_fp = stdout;
if (csql_arg->out_file_name != NULL)
{
csql_Output_fp = fopen (csql_arg->out_file_name, "w");
if (csql_Output_fp == NULL)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
goto fatal_error;
}
}
if (initialize_csql_column_width_info_list () != CSQL_SUCCESS)
{
goto fatal_error;
}
/* For batch file input and csql command argument input */
csql_Tty_fp = NULL;
if (csql_arg->command)
{
/* command input */
csql_exit_session (csql_execute_statements (csql_arg, STRING_INPUT, csql_arg->command, -1), true);
}
if (!csql_Is_interactive && !csql_arg->single_line_execution)
{
csql_exit_session (csql_execute_statements (csql_arg, FILE_INPUT, csql_Input_fp, -1), true);
}
/* Start interactive conversation or single line execution */
if (csql_Is_interactive)
{
csql_Tty_fp = csql_Error_fp;
if (lang_charset () == INTL_CODESET_UTF8)
{
TEXT_CONVERSION *tc = lang_get_txt_conv ();
if (tc != NULL)
{
csql_text_utf8_to_console = tc->utf8_to_text_func;
csql_text_console_to_utf8 = tc->text_to_utf8_func;
}
}
}
/* display product title */
if (!csql_arg->noprint_entrymsg)
{
snprintf (csql_Scratch_text, SCRATCH_TEXT_LEN, csql_get_message (CSQL_INITIAL_CSQL_TITLE), rel_release_string ());
csql_fputs_console_conv (csql_Scratch_text, csql_Tty_fp);
snprintf (csql_Scratch_text, SCRATCH_TEXT_LEN, "\n%s\n\n", csql_get_message (CSQL_INITIAL_HELP_MSG));
csql_fputs_console_conv (csql_Scratch_text, csql_Tty_fp);
}
#if !defined(WINDOWS)
if (csql_Is_interactive)
{
#if defined (ENABLE_UNUSED_FUNCTION)
init_readline ();
#endif /* ENABLE_UNUSED_FUNCTION */
stifle_history (prm_get_integer_value (PRM_ID_CSQL_HISTORY_NUM));
using_history ();
#if defined (ENABLE_UNUSED_FUNCTION)
csql_Keyword_list = pt_get_keyword_rec (&csql_Keyword_num);
#endif /* ENABLE_UNUSED_FUNCTION */
}
#endif /* !WINDOWS */
if (csql_Is_interactive && csql_Prompt_user_defined != CSQL_PROMPT_DEFAULT)
{
change_prompt (csql_Prompt_format, csql_Prompt, sizeof (csql_Prompt));
}
for (line_no = 1;; line_no++)
{
if (db_Connect_status == DB_CONNECTION_STATUS_CONNECTED)
{
prompt = csql_Prompt;
}
else
{
csql_Database_connected = false;
prompt = csql_Prompt_offline;
}
read_whole_line = false;
memset (line_buf, 0, LINE_BUFFER_SIZE);
memset (utf8_line_buf, 0, INTL_UTF8_MAX_CHAR_SIZE * LINE_BUFFER_SIZE);
if (csql_Is_interactive)
{
if (csql_Database_connected && csql_Prompt_user_defined == CSQL_PROMPT_USER_DEFINED_INCLUDE_USERNAME)
{
char *username = db_get_user_name ();
if (strcmp (csql_Prompt_username, username))
{
change_prompt (csql_Prompt_format, csql_Prompt, sizeof (csql_Prompt));
}
if (username)
{
db_string_free (username);
}
}
#if defined(WINDOWS)
fputs (prompt, csql_Output_fp); /* display prompt */
line_read = fgets ((char *) line_buf, LINE_BUFFER_SIZE, csql_Input_fp);
#else
if ((line_read = readline (prompt)) != NULL)
{
if (line_read_alloced != NULL)
{
free (line_read_alloced);
line_read_alloced = NULL;
}
line_read_alloced = line_read;
/* readline assure whole line user typed is located in returned buffer (but it doesn't contain '\n' in
* it) */
read_whole_line = true;
}
#endif /* WINDOWS */
}
else
{
/* If input line exeeds LINE_BUFFER_SIZE, line_buf couldn't contain '\n' character in it. So, read_whole_line
* will be remained as false. */
line_read = fgets ((char *) line_buf, LINE_BUFFER_SIZE, csql_Input_fp);
}
fflush (csql_Output_fp);
if (line_read == NULL)
{
if (errno == EINTR && !feof (csql_Input_fp))
{
fprintf (csql_Output_fp, "\n");
continue;
}
/* Normal end condtion (with -i option) */
if (line_read_alloced != NULL)
{
free (line_read_alloced);
line_read_alloced = NULL;
}
csql_edit_contents_finalize ();
csql_exit_session (0, true);
}
line_length = strlen (line_read);
if (csql_Is_interactive)
{
char *utf8_line_read = NULL;
if (csql_text_console_to_utf8 != NULL)
{
int utf8_line_buf_size = sizeof (utf8_line_buf);
utf8_line_read = (char *) utf8_line_buf;
if ((*csql_text_console_to_utf8) (line_read, line_length, &utf8_line_read, &utf8_line_buf_size) !=
NO_ERROR)
{
goto error_continue;
}
if (utf8_line_read != NULL)
{
line_read = utf8_line_read;
line_length = strlen (line_read);
}
}
}
/* skip UTF-8 BOM if present */
if (is_first_read_line && intl_is_bom_magic (line_read, line_length))
{
line_read += 3;
line_length -= 3;
}
is_first_read_line = false;
for (ptr = line_read + line_length - 1; line_length > 0; ptr--)
{
if (*ptr == '\n')
{
read_whole_line = true;
}
if (*ptr == '\n' || *ptr == '\r')
{
*ptr = '\0';
line_length--;
}
else
{
break;
}
}
if (CSQL_SESSION_COMMAND_PREFIX (line_read[0]) && (csql_Is_interactive || (is_in_block == false)))
{
int ret;
ret = csql_do_session_cmd (line_read, csql_arg);
if (ret == DO_CMD_EXIT || ret == DO_CMD_CONNECT)
{
if (line_read_alloced != NULL)
{
free (line_read_alloced);
line_read_alloced = NULL;
}
csql_edit_contents_finalize ();
if (ret == DO_CMD_EXIT)
{
csql_exit_session (0, true);
}
}
else if (ret == DO_CMD_FAILURE)
{
goto error_continue;
}
if (csql_Is_interactive)
{
line_no = 0;
}
continue;
}
else
{
bool csql_execute = false;
if (csql_edit_contents_append (line_read, read_whole_line) != CSQL_SUCCESS)
{
goto error_continue;
}
if (feof (csql_Input_fp))
{
/* if eof is reached, execute all */
csql_execute = true;
is_in_block = false;
}
else
{
csql_walk_statement (line_read);
/* because we don't want to execute session commands in string block or comment block or identifier block */
is_in_block = csql_is_statement_in_block ();
if (csql_arg->single_line_execution
/* read_whole_line == false means that fgets couldn't read whole line (exceeds buffer size) so we
* should concat next line before execute it. */
&& read_whole_line == true && csql_is_statement_complete ())
{
/* if eof is not reached, execute it only on single line execution mode with complete statement */
csql_execute = true;
}
}
if (csql_execute)
{
/* single-line-oriented execution */
csql_execute_statements (csql_arg, EDITOR_INPUT, NULL, line_no);
csql_edit_contents_clear ();
if (csql_Is_interactive)
{
line_no = 0;
}
}
}
continue;
error_continue:
if (csql_Is_interactive)
{
line_no = 0;
}
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
}
fatal_error:
csql_edit_contents_finalize ();
if (histo_is_supported ())
{
if (csql_Is_histo_on != HISTO_OFF)
{
csql_Is_histo_on = HISTO_OFF;
histo_stop ();
}
}
db_shutdown ();
csql_Database_connected = false;
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
csql_exit (EXIT_FAILURE);
}
static char *
csql_get_external_command (SESSION_CMD cmd_no)
{
switch (cmd_no)
{
case S_CMD_SHELL_CMD:
return csql_Shell_cmd;
case S_CMD_EDIT_CMD:
return csql_Editor_cmd;
case S_CMD_PRINT_CMD:
return csql_Print_cmd;
case S_CMD_PAGER_CMD:
return csql_Pager_cmd;
case S_CMD_FORMATTER_CMD:
return csql_Formatter_cmd;
default:
assert (false);
return NULL;
}
}
static int
csql_do_session_cmd (char *line_read, CSQL_ARGUMENT * csql_arg)
{
char *ptr;
char *sess_end = NULL; /* end pos of session command */
char sess_end_char = '\0'; /* orginal char in end pos of session command */
char *sess_cmd; /* session command pointer */
char *argument; /* argument str */
int cmd_no; /* session command number */
char *argument_end = NULL;
int argument_len = 0;
int error_code;
#if !defined(WINDOWS)
HIST_ENTRY *hist_entry;
#endif /* !WINDOWS */
/* get session command and argument */
ptr = line_read;
if (csql_Is_echo_on)
{
fprintf (csql_Output_fp, "%s\n", line_read);
}
/* 'ptr' points to the prefix char. */
for (ptr++; *ptr != '\0' && iswspace ((wint_t) (*ptr)); ptr++)
{
;
}
sess_cmd = (char *) ptr;
for (; *ptr != '\0' && !iswspace ((wint_t) (*ptr)); ptr++)
{
;
}
if (iswspace ((wint_t) (*ptr)))
{
sess_end = ptr;
sess_end_char = *ptr;
*ptr++ = '\0'; /* put null-termination */
}
else
{
sess_end_char = '\0';
}
for (; *ptr != '\0' && iswspace ((wint_t) (*ptr)); ptr++)
{
;
}
argument = (char *) ptr;
/* remove the end wide-space of argument */
argument_len = strlen (argument);
if (argument_len > 0)
{
argument_end = argument + argument_len - 1;
for (; argument_end != argument && iswspace ((wint_t) (*argument_end)); --argument_end)
{
*argument_end = '\0';
}
}
/* Now, `sess_cmd' points to null-terminated session command name and `argument' points to remaining argument (it may
* be '\0' if not given). */
if (*sess_cmd == '\0' && csql_arg->single_line_execution == false)
{
return DO_CMD_SUCCESS;
}
cmd_no = csql_get_session_cmd_no (sess_cmd);
if (cmd_no == -1)
{
return DO_CMD_FAILURE;
}
/* restore line_read string */
if (sess_end != NULL)
{
*sess_end = sess_end_char;
}
#if !defined(WINDOWS)
if (csql_Is_interactive)
{
add_history (line_read);
}
#endif /* !WINDOWS */
er_clear ();
switch ((SESSION_CMD) cmd_no)
{
/* File stuffs */
case S_CMD_READ: /* read a file */
csql_read_file (argument);
break;
case S_CMD_WRITE: /* write to a file */
case S_CMD_APPEND: /* append to a file */
csql_write_file (argument, cmd_no == S_CMD_APPEND);
break;
case S_CMD_PRINT:
csql_print_buffer ();
break;
case S_CMD_SHELL: /* invoke shell */
csql_invoke_system (csql_Shell_cmd);
csql_fputs ("\n", csql_Tty_fp);
break;
case S_CMD_CD:
csql_change_working_directory (argument);
break;
case S_CMD_EXIT: /* exit */
return DO_CMD_EXIT;
/* Edit stuffs */
case S_CMD_CLEAR: /* clear editor buffer */
csql_edit_contents_clear ();
break;
case S_CMD_EDIT: /* invoke system editor */
if (csql_invoke_system_editor ((argument[0] == '\0') ? NULL : argument) != CSQL_SUCCESS)
{
return DO_CMD_FAILURE;
}
break;
case S_CMD_LIST: /* display buffer */
display_buffer ();
break;
/* Command stuffs */
case S_CMD_RUN:
csql_execute_statements (csql_arg, EDITOR_INPUT, NULL, -1);
break;
case S_CMD_XRUN:
csql_execute_statements (csql_arg, EDITOR_INPUT, NULL, -1);
csql_edit_contents_clear ();
break;
case S_CMD_COMMIT:
if (db_commit_transaction () < 0)
{
csql_display_csql_err (0, 0);
csql_check_server_down ();
}
else
{
csql_display_msg (csql_get_message (CSQL_STAT_COMMITTED_TEXT));
logddl_write_tran_str (LOGDDL_TRAN_TYPE_COMMIT);
}
break;
case S_CMD_ROLLBACK:
if (db_abort_transaction () < 0)
{
csql_display_csql_err (0, 0);
csql_check_server_down ();
}
else
{
csql_display_msg (csql_get_message (CSQL_STAT_ROLLBACKED_TEXT));
logddl_write_tran_str (LOGDDL_TRAN_TYPE_ROLLBACK);
}
break;
case S_CMD_AUTOCOMMIT:
if (!strcasecmp (argument, "on"))
{
csql_arg->auto_commit = true;
}
else if (!strcasecmp (argument, "off"))
{
csql_arg->auto_commit = false;
}
fprintf (csql_Output_fp, "AUTOCOMMIT IS %s\n", (csql_is_auto_commit_requested (csql_arg) ? "ON" : "OFF"));
logddl_set_commit_mode (csql_is_auto_commit_requested (csql_arg));
break;
case S_CMD_CHECKPOINT:
if (csql_arg->sysadm && au_is_dba_group_member (Au_user))
{
error_code = db_checkpoint ();
if (error_code != NO_ERROR)
{
csql_display_csql_err (0, 0);
}
else
{
csql_display_msg (csql_get_message (CSQL_STAT_CHECKPOINT_TEXT));
}
}
else
{
fprintf (csql_Output_fp, "Checkpointing is only allowed for" " the csql started with --sysadm\n");
}
break;
case S_CMD_KILLTRAN:
if (csql_arg->sysadm && au_is_dba_group_member (Au_user))
{
csql_killtran ((argument[0] == '\0') ? NULL : argument);
}
else
{
fprintf (csql_Output_fp, "Killing transaction is only allowed" " for the csql started with --sysadm\n");
}
break;
case S_CMD_RESTART:
if (csql_Database_connected)
{
csql_Database_connected = false;
db_shutdown ();
}
er_init ("./csql.err", ER_NEVER_EXIT);
if (db_restart_ex (UTIL_CSQL_NAME, csql_arg->db_name, csql_arg->user_name, csql_arg->passwd, NULL,
db_get_client_type ()) != NO_ERROR)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
csql_display_csql_err (0, 0);
csql_check_server_down ();
}
else
{
if (csql_arg->sysadm && au_is_dba_group_member (Au_user))
{
int dummy;
AU_DISABLE (dummy);
}
csql_Database_connected = true;
if (csql_arg->trigger_action_flag == false)
{
db_disable_trigger ();
}
csql_display_msg (csql_get_message (CSQL_STAT_RESTART_TEXT));
}
break;
/* Environment stuffs */
case S_CMD_SHELL_CMD:
case S_CMD_EDIT_CMD:
case S_CMD_PRINT_CMD:
case S_CMD_PAGER_CMD:
case S_CMD_FORMATTER_CMD:
if (*argument == '\0')
{
fprintf (csql_Output_fp, "\n\t%s\n\n", csql_get_external_command ((SESSION_CMD) cmd_no));
}
else
{
strncpy (csql_get_external_command ((SESSION_CMD) cmd_no), argument, PATH_MAX - 1);
}
break;
case S_CMD_NOPAGER_CMD:
csql_Pager_cmd[0] = '\0';
break;
/* Help stuffs */
case S_CMD_HELP:
csql_help_menu ();
break;
case S_CMD_SCHEMA:
csql_help_schema ((argument[0] == '\0') ? NULL : argument);
if (csql_is_auto_commit_requested (csql_arg))
{
if (db_commit_transaction () < 0)
{
csql_display_csql_err (0, 0);
csql_check_server_down ();
}
else
{
csql_display_msg (csql_get_message (CSQL_STAT_COMMITTED_TEXT));
}
}
break;
case S_CMD_TRIGGER:
csql_help_trigger ((argument[0] == '\0') ? NULL : argument);
if (csql_is_auto_commit_requested (csql_arg))
{
if (db_commit_transaction () < 0)
{
csql_display_csql_err (0, 0);
csql_check_server_down ();
}
else
{
csql_display_msg (csql_get_message (CSQL_STAT_COMMITTED_TEXT));
}
}
break;
case S_CMD_INFO:
csql_help_info ((argument[0] == '\0') ? NULL : argument, csql_is_auto_commit_requested (csql_arg));
break;
case S_CMD_DATABASE:
csql_print_database ();
break;
case S_CMD_SET_PARAM:
csql_set_sys_param (argument);
break;
case S_CMD_GET_PARAM:
csql_get_sys_param (argument);
break;
case S_CMD_PLAN_DUMP:
csql_set_plan_dump ((argument[0] == '\0') ? NULL : argument);
break;
case S_CMD_ECHO:
if (!strcasecmp (argument, "on"))
{
csql_Is_echo_on = true;
}
else if (!strcasecmp (argument, "off"))
{
csql_Is_echo_on = false;
}
else
{
fprintf (csql_Output_fp, "ECHO IS %s\n", (csql_Is_echo_on ? "ON" : "OFF"));
}
break;
case S_CMD_DATE:
{
time_t tloc = time (NULL);
struct tm tmloc;
char str[80];
utility_localtime (&tloc, &tmloc);
strftime (str, 80, "%a %B %d %H:%M:%S %Z %Y", &tmloc);
fprintf (csql_Output_fp, "\n\t%s\n", str);
}
break;
case S_CMD_TIME:
if (!strcasecmp (argument, "on"))
{
csql_Is_time_on = true;
}
else if (!strcasecmp (argument, "off"))
{
csql_Is_time_on = false;
}
else
{
fprintf (csql_Output_fp, "TIME IS %s\n", (csql_Is_time_on ? "ON" : "OFF"));
}
break;
case S_CMD_LINE_OUTPUT:
if (strcasecmp (argument, "on") == 0)
{
if (csql_arg->column_output)
{
csql_Error_code = CSQL_ERR_INVALID_ARG_COMBINATION;
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
break;
}
csql_arg->line_output = true;
}
else if (strcasecmp (argument, "off") == 0)
{
csql_arg->line_output = false;
}
else
{
fprintf (csql_Output_fp, "LINE_OUTPUT IS %s\n", (csql_arg->line_output ? "ON" : "OFF"));
}
break;
case S_CMD_COLUMN_WIDTH:
{
char *column_name = NULL;
int width = 0, result;
if (*argument == '\0')
{
int i;
for (i = 0; i < csql_column_width_info_list_size; i++)
{
if (csql_column_width_info_list[i].name == NULL)
{
break;
}
if (csql_column_width_info_list[i].width <= 0)
{
continue;
}
fprintf (csql_Output_fp, "COLUMN-WIDTH %s : %d\n", csql_column_width_info_list[i].name,
csql_column_width_info_list[i].width);
}
}
else
{
char *val_str = NULL;
result = get_column_name_argument (&column_name, &val_str, argument);
if (result == CSQL_FAILURE)
{
fprintf (csql_Error_fp, "ERROR: Column name is too long.\n");
break;
}
if (val_str == NULL)
{
width = csql_get_column_width (column_name);
fprintf (csql_Output_fp, "COLUMN-WIDTH %s : %d\n", column_name, width);
}
else
{
trim (val_str);
result = parse_int (&width, val_str, 10);
if (result != 0 || width < 0)
{
fprintf (csql_Error_fp, "ERROR: Invalid argument(%s).\n", val_str);
break;
}
if (csql_set_column_width_info (column_name, width) != CSQL_SUCCESS)
{
return DO_CMD_FAILURE;
}
}
}
}
break;
case S_CMD_STRING_WIDTH:
{
int string_width = 0, result;
if (*argument != '\0')
{
trim (argument);
result = parse_int (&string_width, argument, 10);
if (result != 0 || string_width < 0)
{
fprintf (csql_Error_fp, "ERROR: Invalid string-width(%s).\n", argument);
}
csql_arg->string_width = string_width;
}
else
{
fprintf (csql_Output_fp, "STRING-WIDTH : %d\n", csql_arg->string_width);
}
}
break;
case S_CMD_HISTO:
if (histo_is_supported ())
{
if (!strcasecmp (argument, "on"))
{
if (histo_start (false) == NO_ERROR)
{
csql_Is_histo_on = HISTO_ON;
}
else
{
if (er_errid () == ER_AU_DBA_ONLY)
{
fprintf (csql_Output_fp, "Histogram is allowed only for DBA\n");
}
else
{
fprintf (csql_Output_fp, "Error on .hist command\n");
}
}
}
else if (!strcasecmp (argument, "off"))
{
(void) histo_stop ();
csql_Is_histo_on = HISTO_OFF;
}
else
{
fprintf (csql_Output_fp, ".hist IS %s\n", (csql_Is_histo_on == HISTO_OFF ? "OFF" : "ON"));
}
}
else
{
fprintf (csql_Output_fp,
"Histogram is possible when the csql started with " "`communication_histogram=yes'\n");
}
break;
case S_CMD_CLR_HISTO:
if (histo_is_supported ())
{
if (csql_Is_histo_on == HISTO_ON)
{
histo_clear ();
}
else
{
fprintf (csql_Output_fp, ".hist IS currently OFF\n");
}
}
else
{
fprintf (csql_Output_fp,
"Histogram on execution statistics " "is only allowed for the csql started "
"with `communication_histogram=yes'\n");
}
break;
case S_CMD_DUMP_HISTO:
if (histo_is_supported ())
{
if (csql_Is_histo_on == HISTO_ON)
{
if (histo_print (csql_Output_fp) != NO_ERROR)
{
return DO_CMD_FAILURE;
}
fprintf (csql_Output_fp, "\n");
}
else
{
fprintf (csql_Output_fp, ".hist IS currently OFF\n");
}
}
else
{
fprintf (csql_Output_fp,
"Histogram on execution statistics " "is only allowed for the csql started "
"with `communication_histogram=yes'\n");
}
break;
case S_CMD_DUMP_CLR_HISTO:
if (histo_is_supported ())
{
if (csql_Is_histo_on == HISTO_ON)
{
if (histo_print (csql_Output_fp) != NO_ERROR)
{
return DO_CMD_FAILURE;
}
histo_clear ();
fprintf (csql_Output_fp, "\n");
}
else
{
fprintf (csql_Output_fp, ".hist IS currently OFF\n");
}
}
else
{
fprintf (csql_Output_fp,
"Histogram on execution statistics " "is only allowed for the csql started "
"with `communication_histogram=yes'\n");
}
break;
case S_CMD_HISTORY_READ:
#if !defined(WINDOWS)
if (csql_Is_interactive)
{
if (argument[0] != '\0')
{
int i = atoi (argument);
if (i > 0)
{
HIST_ENTRY *hist;
hist = history_get (history_base + i - 1);
if (hist != NULL)
{
if (csql_edit_contents_append (hist->line, true) != CSQL_SUCCESS)
{
return DO_CMD_FAILURE;
}
}
else
{
fprintf (csql_Error_fp, "ERROR: Invalid history number(%s).\n", argument);
}
}
else
{
fprintf (csql_Error_fp, "ERROR: Invalid history number\n");
}
}
else
{
fprintf (csql_Error_fp, "ERROR: HISTORYRead {history_number}\n");
}
}
#else
if (csql_Is_interactive)
{
fprintf (csql_Error_fp,
"ERROR: Windows do not support HISTORYList" " and HISTORYRead session commands in csql.\n");
}
#endif /* !WINDOWS */
break;
case S_CMD_HISTORY_LIST:
#if !defined(WINDOWS)
if (csql_Is_interactive)
{
for (int i = 0; i < history_length; i++)
{
hist_entry = history_get (i + 1);
if (hist_entry != NULL && hist_entry->line != NULL)
{
fprintf (csql_Output_fp, "----< %d >----\n", i + 1);
fprintf (csql_Output_fp, "%s\n\n", hist_entry->line);
}
}
}
#else
if (csql_Is_interactive)
{
fprintf (csql_Error_fp,
"ERROR: Windows do not support HISTORYList" " and HISTORYRead session commands in csql.\n");
}
#endif /* !WINDOWS */
break;
case S_CMD_TRACE:
if (csql_arg->sa_mode == false)
{
csql_set_trace ((argument[0] == '\0') ? NULL : argument);
}
else
{
fprintf (csql_Error_fp, "Auto trace isn't allowed in SA mode.\n");
}
break;
case S_CMD_SINGLELINE:
if (!strcasecmp (argument, "on"))
{
csql_arg->single_line_execution = true;
}
else if (!strcasecmp (argument, "off"))
{
csql_arg->single_line_execution = false;
}
if (csql_Is_interactive)
{
fprintf (csql_Output_fp, "SINGLELINE IS %s\n", (csql_arg->single_line_execution ? "ON" : "OFF"));
}
break;
case S_CMD_CONNECT:
if (csql_arg->sysadm != true)
{
error_code = csql_connect ((argument[0] == '\0') ? NULL : argument, csql_arg);
if (error_code != NO_ERROR)
{
if (csql_Error_code == NO_ERROR)
{
return DO_CMD_SUCCESS;
}
else
{
return DO_CMD_FAILURE;
}
}
if (csql_Prompt_user_defined != CSQL_PROMPT_DEFAULT)
{
change_prompt (csql_Prompt_format, csql_Prompt, sizeof (csql_Prompt));
}
}
else
{
fprintf (csql_Output_fp, "CONNECT session command does not support --sysadm mode\n");
}
return DO_CMD_CONNECT;
case S_CMD_MIDXKEY:
if (!strcasecmp (argument, "on"))
{
csql_arg->midxkey_print = true;
}
else if (!strcasecmp (argument, "off"))
{
csql_arg->midxkey_print = false;
}
if (csql_Is_interactive)
{
fprintf (csql_Output_fp, "MIDXKEY IS %s\n", (csql_arg->midxkey_print ? "ON" : "OFF"));
}
break;
case S_CMD_SERVER_OUTPUT:
if (strcasecmp (argument, "on") == 0)
{
csql_set_server_output (csql_arg, true);
}
else if (strcasecmp (argument, "off") == 0)
{
csql_set_server_output (csql_arg, false);
}
fprintf (csql_Output_fp, "SERVER OUTPUT IS %s\n", (csql_arg->pl_server_output ? "ON" : "OFF"));
break;
}
return DO_CMD_SUCCESS;
}
/*
* csql_set_server_output() - read a file into command editor
* return: none
* file_name(in): input file name
*/
static void
csql_set_server_output (CSQL_ARGUMENT * csql_arg, bool server_output)
{
csql_arg->pl_server_output = server_output;
if (server_output)
{
csql_execute_query ("CALL dbms_output.enable (50000);");
}
else
{
csql_execute_query ("CALL dbms_output.disable ();");
}
}
/*
* csql_read_file() - read a file into command editor
* return: none
* file_name(in): input file name
*/
static void
csql_read_file (const char *file_name)
{
static char current_file[PATH_MAX] = "";
char *p, *q; /* pointer to string */
FILE *fp = (FILE *) NULL; /* file stream */
p = csql_get_real_path (file_name); /* get real path name */
if (p == NULL || p[0] == '\0')
{
/*
* No filename given; use the last one we were given. If we've
* never received one before we have a genuine error.
*/
if (current_file[0] != '\0')
{
p = current_file;
}
else
{
csql_Error_code = CSQL_ERR_FILE_NAME_MISSED;
goto error;
}
}
for (q = p; *q != '\0' && !iswspace ((wint_t) (*q)); q++)
;
/* trim trailing blanks */
for (; *q != '\0' && iswspace ((wint_t) (*q)); q++)
{
*q = '\0';
}
if (*q != '\0')
{ /* contains more than one file name */
csql_Error_code = CSQL_ERR_TOO_MANY_FILE_NAMES;
goto error;
}
fp = fopen (p, "r");
if (fp == NULL)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
goto error;
}
/*
* We've successfully read the file, so remember its name for
* subsequent reads.
*/
strncpy_bufsize (current_file, p);
if (csql_edit_read_file (fp) == CSQL_FAILURE)
{
goto error;
}
fclose (fp);
csql_display_msg (csql_get_message (CSQL_STAT_READ_DONE_TEXT));
return;
error:
if (fp != NULL)
{
fclose (fp);
}
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
}
/*
* csql_write_file() - write (or append) the current content of editor into
* user specified file
* return: none
* file_name(in): output file name
* append_flag(in): true if append
*/
static void
csql_write_file (const char *file_name, int append_flag)
{
static char current_file[PATH_MAX] = "";
/* the name of the last file written */
char *p, *q; /* pointer to string */
FILE *fp = (FILE *) NULL; /* file stream */
p = csql_get_real_path (file_name); /* get real path name */
if (p == NULL || p[0] == '\0')
{
/*
* No filename given; use the last one we were given. If we've
* never received one before we have a genuine error.
*/
if (current_file[0] != '\0')
p = current_file;
else
{
csql_Error_code = CSQL_ERR_FILE_NAME_MISSED;
goto error;
}
}
for (q = p; *q != '\0' && !iswspace ((wint_t) (*q)); q++)
;
/* trim trailing blanks */
for (; *q != '\0' && iswspace ((wint_t) (*q)); q++)
{
*q = '\0';
}
if (*q != '\0')
{ /* contains more than one file name */
csql_Error_code = CSQL_ERR_TOO_MANY_FILE_NAMES;
goto error;
}
fp = fopen (p, (append_flag) ? "a" : "w");
if (fp == NULL)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
goto error;
}
/*
* We've successfully opened the file, so remember its name for
* subsequent writes.
*/
strncpy_bufsize (current_file, p);
if (csql_edit_write_file (fp) == CSQL_FAILURE)
{
goto error;
}
fclose (fp);
csql_display_msg (csql_get_message (CSQL_STAT_EDITOR_SAVED_TEXT));
return;
error:
if (fp != NULL)
{
fclose (fp);
}
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
}
/*
* csql_print_buffer()
* return: none
*
* Note:
* copy command editor buffer into temporary file and
* invoke the user preferred print command to print
*/
static void
csql_print_buffer (void)
{
/* create an unique file in tmp folder and open it */
auto[filename, fileptr] = filesys::open_temp_file ("csql_");
if (!fileptr)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
return;
}
filesys::auto_delete_file file_del (filename.c_str ()); //deletes file at scope end
filesys::auto_close_file file (fileptr); //closes file at scope end (before the above file deleter); forget about fp from now on
/* write the content of editor to the temp file */
if (csql_edit_write_file (file.get ()) == CSQL_FAILURE)
{
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
return;
}
fflush (file.get ());
/* invoke the print command */
char *cmd = csql_get_tmp_buf (1 + strlen (csql_Print_cmd) + 3 + filename.size ());
if (cmd == NULL)
{
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
return;
}
/*
* Parenthesize the print command and supply its input through stdin,
* just in case it's a pipe or something odd.
*/
sprintf (cmd, "(%s) <%s", csql_Print_cmd, filename.c_str ());
csql_invoke_system (cmd);
free_and_init (cmd);
csql_display_msg (csql_get_message (CSQL_STAT_EDITOR_PRINTED_TEXT));
}
/*
* csql_change_working_directory()
* return: none
* dirname(in)
*
* Note:
* cd to the named directory; if dirname is NULL, cd to
* the home directory.
*/
static void
csql_change_working_directory (const char *dirname)
{
const char *msg;
char buf[100 + PATH_MAX];
msg = csql_get_message (CSQL_STAT_CD_TEXT);
dirname = csql_get_real_path (dirname);
if (dirname == NULL)
{
#if defined (WINDOWS)
static char home_path[PATH_MAX];
sprintf (home_path, "%s%s", getenv ("HOMEDRIVE"), getenv ("HOMEPATH"));
dirname = home_path;
#else
dirname = getenv ("HOME");
#endif
}
if (dirname == NULL || chdir (dirname) == -1)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
}
else
{
snprintf (buf, sizeof (buf) - 1, "\n%s %s.\n\n", msg, dirname);
csql_fputs_console_conv (buf, csql_Tty_fp);
}
}
/*
* display_error()
* return: none
* session(in)
* stmt_start_line_no(in)
*/
static void
display_error (DB_SESSION * session, int stmt_start_line_no)
{
if (csql_Error_code == CSQL_ERR_SQL_ERROR)
{
csql_display_session_err (session, stmt_start_line_no);
csql_check_server_down ();
}
else
{
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
/* let users read this message before the next overwrites */
sleep (3);
}
}
// TODO
/*
* csql_print_server_output()
* return: none
*/
static void
csql_print_server_output (const CSQL_ARGUMENT * csql_arg)
{
int status = 0;
if (csql_arg->pl_server_output == false)
{
return;
}
int errors = csql_execute_query ("EVALUATE '' INTO :pl_output_str");
errors += csql_execute_query ("EVALUATE 1 INTO :pl_output_status");
if (errors != 0)
{
return;
}
bool print_header = true;
do
{
errors = csql_execute_query ("CALL dbms_output.get_line (:pl_output_str, :pl_output_status);");
if (errors != 0)
{
break;
}
DB_VALUE *status_val = pt_find_value_of_label ("pl_output_status");
if (status_val)
{
status = db_get_int (status_val);
if (status == 0)
{
DB_VALUE *str_val = pt_find_value_of_label ("pl_output_str");
if (str_val)
{
if (print_header)
{
print_header = false;
fprintf (csql_Output_fp, "<DBMS_OUTPUT>\n");
fprintf (csql_Output_fp, "====\n");
}
const char *str = db_get_string (str_val);
fprintf (csql_Output_fp, "%s\n", str);
}
else
{
status = 1;
}
}
}
else
{
status = 1;
}
}
while (status == 0);
if (!print_header)
{
// print_header is false if there was at least one server-output line.
fprintf (csql_Output_fp, "\n");
}
}
/*
* csql_execute_statements() - execute statements
* return: >0 if some statement failed, zero otherwise
* csql_arg(in)
* type(in)
* stream(in)
*
* Note:
* If `type' is STRING_INPUT, it regards `stream' points to command string.
* If `type' is FILE_INPUT, it regards `stream' points FILE stream of input
* If `type' is EDITOR_INPUT, it attempts to get input string from command
* buffer.
*/
static int
csql_execute_statements (const CSQL_ARGUMENT * csql_arg, int type, const void *stream, int line_no)
{
char *stmts = NULL; /* statements string */
int num_stmts = 0; /* # of stmts executed */
int stmt_start_line_no = 0; /* starting line no of each stmt */
DB_SESSION *session = NULL; /* query compilation session id */
DB_QUERY_TYPE *attr_spec = NULL; /* result attribute spec. */
int total; /* number of statements to execute */
bool do_abort_transaction = false; /* flag for transaction abort */
csql_Num_failures = 0;
er_clear ();
db_set_interrupt (0);
if (csql_Is_interactive)
{
csql_yyset_lineno (1);
}
if (type == FILE_INPUT)
{ /* FILE * input */
if (!(session = db_open_file ((FILE *) stream)))
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
goto error;
}
logddl_set_csql_input_type (CSQL_INPUT_TYPE_FILE);
logddl_set_load_filename (csql_arg->in_file_name);
}
else if (type == STRING_INPUT)
{ /* string pointer input */
session = db_open_buffer ((const char *) stream);
if (!session)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
goto error;
}
if (csql_Is_echo_on)
{
fprintf (csql_Output_fp, "%s\n", (char *) stream);
}
logddl_set_csql_input_type (CSQL_INPUT_TYPE_STRING);
}
else
{ /* command buffer input */
stmts = csql_edit_contents_get ();
session = db_open_buffer (stmts);
if (!session)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
goto error;
}
if (csql_Is_echo_on)
{
fprintf (csql_Output_fp, "%s\n", stmts);
}
logddl_set_csql_input_type (CSQL_INPUT_TYPE_EDITOR);
}
/*
* Make sure that there weren't any syntax errors; if there were, the
* entire concept of "compile next statement" doesn't make sense, and
* you run the risk of getting stuck in an infinite loop in the
* following section (especially if the '-e' switch is on).
*/
if (db_get_errors (session) || er_errid () != NO_ERROR)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
#if !defined(WINDOWS)
if ((stmts != NULL) && (csql_Is_interactive))
{
add_history (stmts);
}
#endif /* !WINDOWS */
goto error;
}
else
{
total = db_statement_count (session);
#if !defined(WINDOWS)
if ((total >= 1) && (stmts != NULL) && (csql_Is_interactive))
{
add_history (stmts);
}
#endif /* !WINDOWS */
/* It is assumed we must always enter the for loop below */
total = MAX (total, 1);
}
logddl_set_commit_mode (csql_is_auto_commit_requested (csql_arg));
/* execute the statements one-by-one */
for (num_stmts = 0; num_stmts < total; num_stmts++)
{
TSC_TICKS start_tick, end_tick, start_commit_tick, end_commit_tick;
TSCTIMEVAL elapsed_time;
int stmt_id;
CUBRID_STMT_TYPE stmt_type; /* statement type */
DB_QUERY_RESULT *result = NULL; /* result pointer */
int db_error;
char stmt_msg[LINE_BUFFER_SIZE];
/* Start the execution of stms */
stmt_msg[0] = '\0';
if (csql_Is_time_on)
{
tsc_getticks (&start_tick);
}
logddl_set_start_time (NULL);
stmt_id = db_compile_statement (session);
assert ((stmt_id < 0) || stmt_id == (num_stmts + 1));
if (session->statements && session->statements[num_stmts])
{
int t_type = (CUBRID_STMT_TYPE) db_get_statement_type (session, num_stmts + 1);
logddl_check_and_set_query_text (session->statements[num_stmts], t_type, session->parser);
}
if (stmt_id <= 0)
{
if (stmt_id == 0) /* done */
{
break;
}
/*
* Transaction should be aborted if an error occurs during
* compilation on auto commit mode.
*/
if (csql_is_auto_commit_requested (csql_arg))
{
do_abort_transaction = true;
}
logddl_set_err_code (db_error_code ());
/* compilation error */
csql_Error_code = CSQL_ERR_SQL_ERROR;
/* Do not continue if there are no statments in the buffer */
if (csql_arg->continue_on_error && (db_error_code () != ER_IT_EMPTY_STATEMENT))
{
display_error (session, 0);
/* do_abort_transaction() should be called after display_error() because in some cases it deallocates the
* parser containing the error message */
if (do_abort_transaction)
{
db_abort_transaction ();
do_abort_transaction = false;
logddl_set_msg (LOGDDL_MSG_AUTO_ROLLBACK);
}
csql_Num_failures += 1;
logddl_write_end ();
continue;
}
else
{
goto error;
}
}
if (line_no == -1)
{
stmt_start_line_no = db_get_start_line (session, stmt_id);
}
else
{
stmt_start_line_no = line_no;
}
attr_spec = db_get_query_type_list (session, stmt_id);
stmt_type = (CUBRID_STMT_TYPE) db_get_statement_type (session, stmt_id);
if (db_set_statement_auto_commit (session, csql_is_auto_commit_requested (csql_arg)) != NO_ERROR)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
goto error;
}
db_error = db_execute_statement (session, stmt_id, &result);
if (db_error < 0)
{
logddl_set_err_code (db_error_code ());
csql_Error_code = CSQL_ERR_SQL_ERROR;
if (csql_is_auto_commit_requested (csql_arg) && stmt_type != CUBRID_STMT_ROLLBACK_WORK)
{
do_abort_transaction = true;
}
if (csql_arg->continue_on_error)
{
display_error (session, stmt_start_line_no);
if (do_abort_transaction)
{
db_abort_transaction ();
do_abort_transaction = false;
logddl_set_msg (LOGDDL_MSG_AUTO_ROLLBACK);
}
csql_Num_failures += 1;
free_attr_spec (&attr_spec);
logddl_write_end ();
continue;
}
goto error;
}
if (csql_Is_time_on)
{
tsc_getticks (&end_tick);
tsc_elapsed_time_usec (&elapsed_time, end_tick, start_tick);
}
snprintf (stmt_msg, LINE_BUFFER_SIZE, "Execute OK.");
csql_Row_count = 0;
switch (stmt_type)
{
case CUBRID_STMT_SELECT:
{
const char *msg_p;
csql_results (csql_arg, result, attr_spec, stmt_start_line_no, stmt_type);
csql_Row_count = db_error;
msg_p = ((csql_Row_count > 1) ? csql_get_message (CSQL_ROWS) : csql_get_message (CSQL_ROW));
snprintf (stmt_msg, LINE_BUFFER_SIZE, msg_p, csql_Row_count, "selected");
break;
}
case CUBRID_STMT_CALL:
case CUBRID_STMT_EVALUATE:
if (result != NULL)
{
// Results can be values other than NULL
csql_results (csql_arg, result, db_get_query_type_ptr (result), stmt_start_line_no, stmt_type);
}
break;
case CUBRID_STMT_GET_ISO_LVL:
case CUBRID_STMT_GET_TIMEOUT:
case CUBRID_STMT_GET_OPT_LVL:
case CUBRID_STMT_GET_TRIGGER:
case CUBRID_STMT_GET_STATS:
if (result != NULL)
{
csql_results (csql_arg, result, db_get_query_type_ptr (result), stmt_start_line_no, stmt_type);
}
break;
case CUBRID_STMT_UPDATE:
case CUBRID_STMT_DELETE:
case CUBRID_STMT_INSERT:
case CUBRID_STMT_MERGE:
{
const char *msg_p;
msg_p = ((db_error > 1) ? csql_get_message (CSQL_ROWS) : csql_get_message (CSQL_ROW));
snprintf (stmt_msg, LINE_BUFFER_SIZE, msg_p, db_error, "affected");
break;
}
case CUBRID_STMT_KILL:
{
const char *msg_p;
msg_p = ((db_error > 1) ? csql_get_message (CSQL_TRANSACTIONS) : csql_get_message (CSQL_TRANSACTION));
snprintf (stmt_msg, LINE_BUFFER_SIZE, msg_p, db_error, "killed");
break;
}
default:
break;
}
free_attr_spec (&attr_spec);
if (result != NULL)
{
db_query_end (result);
result = NULL;
}
else
{
/*
* Even though there are no results, a query may have been
* run implicitly by the statement. If so, we need to end the
* query on the server.
*/
db_free_query (session);
}
if (csql_Is_time_on)
{
char time[100];
sprintf (time, " (%ld.%06ld sec) ", elapsed_time.tv_sec, elapsed_time.tv_usec);
strncat (stmt_msg, time, sizeof (stmt_msg) - strlen (stmt_msg) - 1);
}
if (csql_is_auto_commit_requested (csql_arg) && stmt_type != CUBRID_STMT_COMMIT_WORK
&& stmt_type != CUBRID_STMT_ROLLBACK_WORK)
{
if (csql_Is_time_on)
{
tsc_getticks (&start_commit_tick);
}
db_error = db_commit_transaction ();
if (db_error < 0)
{
logddl_set_err_code (db_error_code ());
csql_Error_code = CSQL_ERR_SQL_ERROR;
do_abort_transaction = true;
if (csql_arg->continue_on_error)
{
display_error (session, stmt_start_line_no);
if (do_abort_transaction)
{
db_abort_transaction ();
do_abort_transaction = false;
logddl_set_msg (LOGDDL_MSG_AUTO_ROLLBACK);
}
csql_Num_failures += 1;
logddl_write_end ();
continue;
}
goto error;
}
else
{
strncat (stmt_msg, csql_get_message (CSQL_STAT_COMMITTED_TEXT), LINE_BUFFER_SIZE - 1);
if (csql_Is_time_on)
{
char time[100];
tsc_getticks (&end_commit_tick);
tsc_elapsed_time_usec (&elapsed_time, end_commit_tick, start_commit_tick);
sprintf (time, " (%ld.%06ld sec) ", elapsed_time.tv_sec, elapsed_time.tv_usec);
strncat (stmt_msg, time, sizeof (stmt_msg) - strlen (stmt_msg) - 1);
}
}
}
if (csql_is_auto_commit_requested (csql_arg) == false && (stmt_type == CUBRID_STMT_COMMIT_WORK
|| stmt_type == CUBRID_STMT_ROLLBACK_WORK))
{
if (stmt_type == CUBRID_STMT_COMMIT_WORK)
{
(type !=
FILE_INPUT) ? logddl_write_tran_str (LOGDDL_TRAN_TYPE_COMMIT) :
logddl_write_tran_str ("Commit transaction at line %d", stmt_start_line_no);
}
else if (stmt_type == CUBRID_STMT_ROLLBACK_WORK)
{
(type !=
FILE_INPUT) ? logddl_write_tran_str (LOGDDL_TRAN_TYPE_ROLLBACK) :
logddl_write_tran_str ("Rollback transaction at line %d", stmt_start_line_no);
}
}
if (csql_arg->pl_server_output)
{
csql_print_server_output (csql_arg);
}
if (csql_arg->plain_output == false && csql_arg->query_output == false && csql_arg->loaddb_output == false)
{
fprintf (csql_Output_fp, "%s\n", stmt_msg);
}
db_drop_statement (session, stmt_id);
if (type != FILE_INPUT)
{
if (csql_is_auto_commit_requested (csql_arg))
{
logddl_set_msg (LOGDDL_MSG_AUTO_COMMIT);
}
logddl_write_end ();
}
}
if (csql_arg->sysadm_rebuild_catalog)
{
if (csql_rebuild_catalog (csql_arg) != NO_ERROR)
{
csql_Error_code = CSQL_ERR_SYSTEM_CATALOG_COMPILE;
goto error;
}
}
snprintf (csql_Scratch_text, SCRATCH_TEXT_LEN, csql_get_message (CSQL_EXECUTE_END_MSG_FORMAT),
num_stmts - csql_Num_failures);
csql_display_msg (csql_Scratch_text);
if (type == FILE_INPUT)
{
logddl_write_end_for_csql_fileinput ("Total %8d statements executed. %8d statements failed.", total,
csql_Num_failures);
}
db_close_session (session);
if (csql_Query_trace == true)
{
csql_display_trace ();
}
if (csql_is_auto_commit_requested (csql_arg))
{
logddl_free (true);
}
return csql_Num_failures;
error:
if (csql_arg->sysadm_rebuild_catalog)
{
do_abort_transaction = true;
}
display_error (session, stmt_start_line_no);
if (csql_arg->pl_server_output)
{
csql_print_server_output (csql_arg);
}
logddl_set_err_code (db_error_code ());
if (do_abort_transaction)
{
db_abort_transaction ();
do_abort_transaction = false;
logddl_set_msg (LOGDDL_MSG_AUTO_ROLLBACK);
}
else
{
(void) db_reset_latest_query_status ();
}
/* Finish... */
snprintf (csql_Scratch_text, SCRATCH_TEXT_LEN, csql_get_message (CSQL_EXECUTE_END_MSG_FORMAT),
num_stmts - csql_Num_failures);
csql_display_msg (csql_Scratch_text);
(type == FILE_INPUT) ? logddl_write_end_for_csql_fileinput ("") : logddl_write_end ();
if (session)
{
db_close_session (session);
}
free_attr_spec (&attr_spec);
if (csql_is_auto_commit_requested (csql_arg))
{
logddl_free (true);
}
return 1;
}
/*
* free_attr_spec()
* return: none
* attr_spec(in/out)
*
* Note: Free memory alloced for attr_spec and set pointer to NULL
*/
static void
free_attr_spec (DB_QUERY_TYPE ** attr_spec)
{
if (*attr_spec != NULL)
{
db_query_format_free (*attr_spec);
*attr_spec = NULL;
}
}
/*
* csql_print_database()
*/
static void
csql_print_database (void)
{
struct sockaddr_in sin;
const char *db_name, *host_name;
char *pstr;
char converted_host_name[CUB_MAXHOSTNAMELEN + 1];
char ha_state[16];
int res;
db_name = db_get_database_name ();
host_name = db_get_host_connected ();
if (db_name == NULL || host_name == NULL)
{
fprintf (csql_Error_fp, "\n\tNOT CONNECTED\n\n");
}
else
{
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr (host_name);
res =
getnameinfo_uhost ((struct sockaddr *) &sin, sizeof (sin), converted_host_name, sizeof (converted_host_name),
NULL, 0, NI_NAMEREQD);
/*
* if it fails to resolves hostname,
* it will use db_get_host_connected()'s result.
*/
if (res != 0)
{
strncpy (converted_host_name, host_name, CUB_MAXHOSTNAMELEN);
converted_host_name[CUB_MAXHOSTNAMELEN] = '\0';
}
if (strcasecmp (converted_host_name, "localhost") == 0
|| strcasecmp (converted_host_name, "localhost.localdomain") == 0)
{
if (GETHOSTNAME (converted_host_name, CUB_MAXHOSTNAMELEN) != 0)
{
strncpy (converted_host_name, host_name, CUB_MAXHOSTNAMELEN);
}
}
converted_host_name[CUB_MAXHOSTNAMELEN] = '\0';
/*
* if there is hostname or ip address in db_name,
* it will only use db_name except for hostname or ip address.
*/
pstr = (char *) strchr (db_name, '@');
if (pstr != NULL)
{
*pstr = '\0';
}
if (HA_DISABLED ())
{
fprintf (csql_Output_fp, "\n\t%s@%s\n\n", db_name, converted_host_name);
}
else
{
db_get_ha_server_state (ha_state, 16);
fprintf (csql_Output_fp, "\n\t%s@%s [%s]\n\n", db_name, converted_host_name, ha_state);
}
db_ws_free ((char *) db_name);
}
}
/*
* csql_set_sys_param()
* return: none
* arg_str(in)
*
* Note: Parse the arg string to find out what system parameter to
* clobber, then clobber it. Originally introduced to allow us
* to fiddle with optimizer parameters.
*/
static void
csql_set_sys_param (const char *arg_str)
{
char plantype[128];
char val[128];
char ans[4096];
int level;
int len = sizeof (ans);
if (arg_str == NULL)
return;
if (strncmp (arg_str, "cost", 4) == 0 && sscanf (arg_str, "cost %127s %127s", plantype, val) == 2)
{
if (qo_plan_set_cost_fn (plantype, val[0]))
{
snprintf (ans, len - 1, "cost %s: %s", plantype, val);
}
else
{
snprintf (ans, len - 1, "error: unknown cost parameter %s", plantype);
}
}
else if (strncmp (arg_str, "level", 5) == 0 && sscanf (arg_str, "level %d", &level) == 1)
{
if (CHECK_INVALID_OPTIMIZATION_LEVEL (level))
{
snprintf (ans, len - 1, "error: wrong value %d", level);
}
else
{
qo_set_optimization_param (NULL, QO_PARAM_LEVEL, level);
strncpy (ans, arg_str, len - 1);
}
}
else
{
strncpy (ans, arg_str, len - 1);
if (db_set_system_parameters (ans) != NO_ERROR)
{
snprintf (ans, len, "error: set %s", arg_str);
}
}
csql_append_more_line (0, ans);
csql_display_more_lines ("Set Param Input");
csql_free_more_lines ();
}
/*
* csql_get_sys_param()
* return:
* arg_str(in)
*/
static void
csql_get_sys_param (const char *arg_str)
{
char plantype[128];
int cost;
char ans[4096];
int level;
int len = sizeof (ans);
if (arg_str == NULL)
return;
if (strncmp (arg_str, "cost", 4) == 0 && sscanf (arg_str, "cost %127s", plantype) == 1)
{
cost = qo_plan_get_cost_fn (plantype);
if (cost == 'u')
{
snprintf (ans, len, "error: unknown cost parameter %s", arg_str);
}
else
{
snprintf (ans, len, "cost %s: %c", arg_str, (char) cost);
}
}
else if (strcmp (arg_str, "level") == 0)
{
qo_get_optimization_param (&level, QO_PARAM_LEVEL);
snprintf (ans, len, "level %d", level);
}
else
{
strncpy (ans, arg_str, len - 1);
if (db_get_system_parameters (ans, len - 1) != NO_ERROR)
{
snprintf (ans, len - 1, "error: get %s", arg_str);
}
}
csql_append_more_line (0, ans);
csql_display_more_lines ("Get Param Input");
csql_free_more_lines ();
}
/*
* csql_set_plan_dump()
* return:
* arg_str(in)
*/
static void
csql_set_plan_dump (const char *arg_str)
{
int level;
char line[128];
qo_get_optimization_param (&level, QO_PARAM_LEVEL);
if (arg_str != NULL)
{
if (!strncmp (arg_str, "simple", 6))
{
level &= ~0x200;
level |= 0x100;
qo_set_optimization_param (NULL, QO_PARAM_LEVEL, level);
}
else if (!strncmp (arg_str, "detail", 6))
{
level &= ~0x100;
level |= 0x200;
qo_set_optimization_param (NULL, QO_PARAM_LEVEL, level);
}
else if (!strncmp (arg_str, "off", 3))
{
level &= ~(0x100 | 0x200);
qo_set_optimization_param (NULL, QO_PARAM_LEVEL, level);
}
}
if (PLAN_DUMP_ENABLED (level))
{
if (SIMPLE_DUMP (level))
{
snprintf (line, 128, "plan simple (opt level %d)", level);
}
if (DETAILED_DUMP (level))
{
snprintf (line, 128, "plan detail (opt level %d)", level);
}
}
else
{
snprintf (line, 128, "plan off (opt level %d)", level);
}
csql_append_more_line (0, line);
csql_display_more_lines ("Plan Dump");
csql_free_more_lines ();
}
/*
* signal_intr() - Interrupt handler for csql
* return: none
* sig_no(in)
*/
#if defined(WINDOWS)
static BOOL WINAPI
#else /* !WINDOWS */
static void
#endif /* WINDOWS */
signal_intr (int sig_no)
{
if (csql_Is_interactive)
{
db_set_interrupt (1);
}
csql_Is_sigint_caught = true;
#if defined(WINDOWS)
if (sig_no == CTRL_C_EVENT)
{
return TRUE;
}
return FALSE;
#endif /* WINDOWS */
}
/*
* signal_stop()
* return: none
* sig_no(in)
*
* Note: Interrupt handler for ^Z. This is needed since the terminal
* must be changed from raw to cooked. After we return, it must
* be set back.
*/
static void
signal_stop (int sig_no)
{
static int cont = 0;
#if defined(WINDOWS)
/* there is no SIGSTP on NT */
cont = 1;
#else /* !WINDOWS */
if (sig_no == SIGTSTP)
{
cont = 0;
(void) os_set_signal_handler (SIGTSTP, SIG_DFL);
/* send the signal to ourselves */
os_send_signal (SIGTSTP);
/* Wait for SIGCONT */
while (cont == 0)
{
pause ();
}
(void) os_set_signal_handler (SIGTSTP, signal_stop);
}
else
{
/* Continue */
cont = 1;
}
#endif /* !WINDOWS */
}
#if !defined(WINDOWS)
/*
* crash_handler(): kill the server and spawn the new server process
*
* returns: none
* signo(IN): signo to handle
* siginfo(IN): siginfo struct
* dummyp(IN): this argument will not be used,
* but remains to cope with its function prototype.
*
*/
static void
crash_handler (int signo, siginfo_t * siginfo, void *dummyp)
{
if (os_set_signal_handler (signo, SIG_DFL) == SIG_ERR)
{
return;
}
er_print_crash_callstack (signo);
}
/*
* register_crash_signal_handler () : register of the signal for occuring crash
*
* returns : none
* signo(IN): signo to handle
*
*/
static void
register_crash_signal_handler (int signo)
{
struct sigaction act;
act.sa_handler = NULL;
act.sa_sigaction = crash_handler;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
act.sa_flags |= SA_SIGINFO;
sigaction (signo, &act, NULL);
}
#endif
/*
* csql_exit_session() - handling the default action of the last outstanding
* transaction (i.e., commit or abort)
* return: none
* error(in)
*
* Note: this function never return.
*/
static void
csql_exit_session (int error, bool exit_flag)
{
char line_buf[LINE_BUFFER_SIZE];
bool commit_on_shutdown = false;
bool prm_commit_on_shutdown = prm_get_commit_on_shutdown ();
free_csql_column_width_info_list ();
if (!db_commit_is_needed ())
{
/* when select statements exist only in session, marks end of transaction to flush audit records for those
* statements */
db_abort_transaction ();
}
if (csql_Is_interactive && !prm_commit_on_shutdown && db_commit_is_needed () && !feof (csql_Input_fp))
{
FILE *tf;
tf = csql_Error_fp;
/* interactive, default action is abort but there was update */
fprintf (tf, csql_get_message (CSQL_TRANS_TERMINATE_PROMPT_TEXT));
fflush (tf);
for (; fgets (line_buf, LINE_BUFFER_SIZE, csql_Input_fp) != NULL;)
{
if (line_buf[0] == 'y' || line_buf[0] == 'Y')
{
commit_on_shutdown = true;
logddl_write_tran_str (LOGDDL_TRAN_TYPE_COMMIT);
break;
}
if (line_buf[0] == 'n' || line_buf[0] == 'N')
{
commit_on_shutdown = false;
logddl_write_tran_str (LOGDDL_TRAN_TYPE_ROLLBACK);
break;
}
fprintf (tf, csql_get_message (CSQL_TRANS_TERMINATE_PROMPT_RETRY_TEXT));
fflush (tf);
}
if (commit_on_shutdown && db_commit_transaction () < 0)
{
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
error = 1;
}
}
if (!exit_flag)
{
return;
}
if (histo_is_supported ())
{
if (csql_Is_histo_on != HISTO_OFF)
{
csql_Is_histo_on = HISTO_OFF;
histo_stop ();
}
}
if (db_shutdown () < 0)
{
csql_Database_connected = false;
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
csql_exit (EXIT_FAILURE);
}
else
{
csql_Database_connected = false;
csql_exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
}
}
/*
* csql_exit_init()
* return: none
*
* Note:
* Initialize various state variables we keep to let us know what
* cleanup operations need to be performed when the csql() function
* exits. This should properly initialize everything that is tested
* by the csql_exit_cleanup function.
*/
static void
csql_exit_init (void)
{
csql_Exit_status = EXIT_SUCCESS;
csql_Database_connected = false;
csql_Input_fp = stdin;
csql_Output_fp = stdout;
csql_Error_fp = stderr;
}
/*
* csql_exit_cleanup()
* return: none
*
* Note:
* Called by csql() when the exit longjmp has been taken.
* Examine the various state variables we keep and perform any
* termination cleanup operations that need to be performed.
* For the Windows implementation, it is especially important that the
* csql() function return cleanly.
*/
static void
csql_exit_cleanup ()
{
FILE *oldout;
if (csql_Input_fp != NULL && csql_Input_fp != stdin)
{
(void) fclose (csql_Input_fp);
csql_Input_fp = NULL;
}
oldout = csql_Output_fp;
if (csql_Output_fp != NULL && csql_Output_fp != stdout)
{
(void) fclose (csql_Output_fp);
csql_Output_fp = NULL;
}
if (csql_Error_fp != NULL && csql_Error_fp != oldout && csql_Error_fp != stdout && csql_Error_fp != stderr)
{
(void) fclose (csql_Error_fp);
csql_Error_fp = NULL;
}
if (csql_Database_connected)
{
if (histo_is_supported ())
{
if (csql_Is_histo_on != HISTO_OFF)
{
csql_Is_histo_on = HISTO_OFF;
histo_stop ();
}
}
csql_Database_connected = false;
db_shutdown ();
}
/* Note that this closes a global resource, the "kernel" message catalog. This is ok for the Unix implementation as
* the entire process is about to exit. For the Windows implementation, it happens to be ok since the test driver
* application that calls csql() won't use this catalog. If this ever changes however, we'll probably have to
* maintain some sort of internal reference counter on this catalog so that it won't be freed until all the nested
* users close it. */
lang_final ();
}
/*
* csql_exit()
* return: none
* exit_status(in)
* Note:
* This should be called rather than exit() any place that the code wants
* to terminate the csql interpreter program. Rather than exit(), it
* will longjmp back to the csql() function which will clean up and
* return the status code to the calling function. Usually the calling
* function is main() but under Windows, the caller may be a more complex
* application.
*/
void
csql_exit (int exit_status)
{
csql_Exit_status = exit_status;
longjmp (csql_Exit_env, 1);
}
/* --sysadm-rebuild-catalog option is only supported in SA_MODE */
static inline void
csql_apply_catalog_rebuild_mode (CSQL_ARGUMENT * csql_arg, int *client_type)
{
#if defined (SA_MODE)
*client_type = DB_CLIENT_TYPE_ADMIN_CSQL_REBUILD_CATALOG;
csql_arg->sysadm = true;
csql_arg->auto_commit = false;
boot_set_skip_check_ct_classes (true);
#endif /* SA_MODE */
}
static int
csql_rebuild_catalog (const CSQL_ARGUMENT * csql_arg)
{
#if defined (SA_MODE)
assert (catcls_Enable == false);
if (catcls_compile_catalog_classes (NULL) != NO_ERROR)
{
return ER_FAILED;
}
if (sm_force_write_all_classes () != NO_ERROR)
{
return ER_FAILED;
}
if (sm_update_all_catalog_statistics (STATS_WITH_FULLSCAN) != NO_ERROR)
{
return ER_FAILED;
}
db_commit_transaction ();
#endif /* SA_MODE */
return NO_ERROR;
}
/*
* csql() - "main" interface function for the csql interpreter
* return: EXIT_SUCCESS, EXIT_FAILURE
* csql_arg(in)
*/
int
csql (const char *argv0, CSQL_ARGUMENT * csql_arg)
{
char *env;
int client_type;
int avail_size;
int save;
char *p = NULL;
unsigned char ip_addr[16] = { 0 };
/* Establish a globaly accessible longjmp environment so we can terminate on severe errors without calling exit(). */
csql_exit_init ();
if (setjmp (csql_Exit_env))
{
/* perform any dangling cleanup operations */
csql_exit_cleanup ();
logddl_destroy ();
return csql_Exit_status;
}
/* initialize message catalog for argument parsing and usage() */
if (utility_initialize () != NO_ERROR)
{
csql_exit (EXIT_FAILURE);
}
/* set up prompt and message fields. */
if (csql_arg->sysadm)
{
strncpy_bufsize (csql_Prompt, csql_get_message (CSQL_SYSADM_PROMPT));
}
else
{
strncpy_bufsize (csql_Prompt, csql_get_message (CSQL_PROMPT));
}
avail_size = sizeof (csql_Prompt) - strlen (csql_Prompt) - 1;
if (avail_size > 0)
{
strncat (csql_Prompt, " ", avail_size);
}
snprintf (csql_Prompt_offline, sizeof (csql_Prompt_offline), "!%s", csql_Prompt);
/* as we must use db_open_file_name() to open the input file, it is necessary to be opening csql_Input_fp at this
* point */
if (csql_arg->in_file_name != NULL)
{
#if defined(WINDOWS)
csql_Input_fp = fopen (csql_arg->in_file_name, "rb");
#else /* !WINDOWS */
csql_Input_fp = fopen (csql_arg->in_file_name, "r");
#endif /* WINDOWS */
if (csql_Input_fp == NULL)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
goto error;
}
#if defined(WINDOWS)
{
char tmpchar; /* open breaks in DLL'S */
/*
* Unless an operation is done on this stream before the DLL
* is entered the file descriptor will be invalid. This is a bug in
* MSVC compiler and/or libc.
*/
tmpchar = fgetc (csql_Input_fp);
ungetc (tmpchar, csql_Input_fp);
}
#endif /* WINDOWS */
}
if ((csql_arg->in_file_name == NULL) && isatty (fileno (stdin)))
{
csql_Is_interactive = true;
}
/* initialize error log file */
if (er_init ("./csql.err", ER_NEVER_EXIT) != NO_ERROR)
{
printf ("Failed to initialize error manager.\n");
csql_Error_code = CSQL_ERR_OS_ERROR;
goto error;
}
#if !defined(WINDOWS)
/* set signal handler */
register_crash_signal_handler (SIGABRT);
register_crash_signal_handler (SIGILL);
register_crash_signal_handler (SIGFPE);
register_crash_signal_handler (SIGBUS);
register_crash_signal_handler (SIGSEGV);
register_crash_signal_handler (SIGSYS);
#endif
/*
* login and restart database
*/
if (csql_arg->sysadm)
{
client_type = DB_CLIENT_TYPE_ADMIN_CSQL;
if (csql_arg->write_on_standby)
{
client_type = DB_CLIENT_TYPE_ADMIN_CSQL_WOS;
}
else if (csql_arg->skip_vacuum)
{
client_type = DB_CLIENT_TYPE_SKIP_VACUUM_ADMIN_CSQL;
}
}
else if (csql_arg->read_only)
{
client_type = DB_CLIENT_TYPE_READ_ONLY_CSQL;
}
else if (csql_arg->skip_vacuum)
{
client_type = DB_CLIENT_TYPE_SKIP_VACUUM_CSQL;
}
else
{
client_type = DB_CLIENT_TYPE_CSQL;
}
if (csql_arg->sysadm_rebuild_catalog)
{
csql_apply_catalog_rebuild_mode (csql_arg, &client_type);
}
if (db_restart_ex (argv0, csql_arg->db_name, csql_arg->user_name, csql_arg->passwd, NULL, client_type) != NO_ERROR)
{
if (!csql_Is_interactive || csql_arg->passwd != NULL || db_error_code () != ER_AU_INVALID_PASSWORD)
{
/* not INTERACTIVE mode, or password is given already, or the error code is not password related */
csql_Error_code = CSQL_ERR_SQL_ERROR;
goto error;
}
/* get password interactively if interactive mode */
p = getpass ((char *) csql_get_message (CSQL_PASSWD_PROMPT_TEXT));
if (p[0] == '\0')
{
csql_arg->passwd = (char *) NULL; /* to fit into db_login protocol */
}
else
{
csql_arg->passwd = strdup (p);
}
/* try again */
if (db_restart_ex (argv0, csql_arg->db_name, csql_arg->user_name, csql_arg->passwd, NULL, client_type) !=
NO_ERROR)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
goto error;
}
}
er_set_print_property (ER_PRINT_TO_CONSOLE);
logddl_init (APP_NAME_CSQL);
logddl_check_ddl_audit_param ();
if (get_host_ip (ip_addr) == 0)
{
logddl_set_ip ((char *) ip_addr);
db_set_client_ip_addr ((char *) ip_addr);
}
if (csql_arg->trigger_action_flag == false)
{
db_disable_trigger ();
}
if (csql_arg->sysadm && au_is_dba_group_member (Au_user))
{
AU_DISABLE (save);
}
/* allow environmental setting of the "-s" command line flag to enable automated testing */
if (prm_get_bool_value (PRM_ID_CSQL_SINGLE_LINE_MODE))
{
csql_arg->single_line_execution = true;
}
/* record the connection so we know how to clean up on exit */
csql_Database_connected = true;
#if defined(CSQL_NO_LOGGING)
if (csql_arg->no_logging && locator_log_force_nologging () != NO_ERROR)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
goto error;
}
#endif /* CSQL_NO_LOGGING */
csql_Editor_cmd[PATH_MAX - 1] = '\0';
csql_Shell_cmd[PATH_MAX - 1] = '\0';
csql_Print_cmd[PATH_MAX - 1] = '\0';
csql_Pager_cmd[PATH_MAX - 1] = '\0';
csql_Formatter_cmd[PATH_MAX - 1] = '\0';
env = getenv ("CUBRID_CSQL_EDITOR");
env = env != NULL ? env : getenv ("EDITOR");
if (env)
{
strncpy (csql_Editor_cmd, env, PATH_MAX - 1);
}
env = getenv ("CUBRID_CSQL_SHELL");
env = env != NULL ? env : getenv ("SHELL");
if (env)
{
strncpy (csql_Shell_cmd, env, PATH_MAX - 1);
}
env = getenv ("CUBRID_CSQL_FORMATTER");
env = env != NULL ? env : getenv ("FORMATTER");
if (env)
{
strncpy (csql_Formatter_cmd, env, PATH_MAX - 1);
}
env = getenv ("CUBRID_CSQL_PROMPT");
if (!csql_arg->sysadm && env && *env != '\0')
{
csql_Prompt_user_defined = CSQL_PROMPT_USER_DEFINED;
strcpy (csql_Prompt_format, env);
}
if (csql_arg->nopager)
{
csql_Pager_cmd[0] = '\0';
}
lang_init_console_txt_conv ();
if (csql_Is_interactive)
{
/* handling Ctrl-C */
#if defined(WINDOWS)
SetConsoleCtrlHandler ((PHANDLER_ROUTINE) signal_intr, TRUE);
#else
if (os_set_signal_handler (SIGINT, signal_intr) == SIG_ERR)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
goto error;
}
#endif
#if !defined(WINDOWS)
if (os_set_signal_handler (SIGQUIT, signal_intr) == SIG_ERR)
{
csql_Error_code = CSQL_ERR_OS_ERROR;
goto error;
}
#endif /* !WINDOWS */
}
er_set_print_property (ER_DO_NOT_PRINT);
start_csql (csql_arg);
csql_exit (EXIT_SUCCESS); /* not reachable code, actually */
error:
nonscr_display_error (csql_Scratch_text, SCRATCH_TEXT_LEN);
csql_exit (EXIT_FAILURE);
er_final (ER_ALL_FINAL);
return EXIT_FAILURE; /* won't get here really */
}
/*
* csql_get_message() - get a string of the csql-utility from the catalog
* return: message string
* message_index(in): an index of the message string
*/
const char *
csql_get_message (int message_index)
{
return (msgcat_message (MSGCAT_CATALOG_CSQL, MSGCAT_CSQL_SET_CSQL, message_index));
}
/*
* csql_set_column_width_info() - insert column_name and column_width
* in csql_column_width_info_list
* return: int
* column_name(in): column_name
* column_width(in): column_width
*/
int
csql_set_column_width_info (const char *column_name, int column_width)
{
CSQL_COLUMN_WIDTH_INFO *temp_list;
char *temp_name;
int i, index;
if (column_name == NULL || column_width < 0)
{
csql_Error_code = CSQL_ERR_INVALID_ARG_COMBINATION;
return CSQL_FAILURE;
}
if (csql_column_width_info_list == NULL)
{
if (initialize_csql_column_width_info_list () != CSQL_SUCCESS)
{
return CSQL_FAILURE;
}
}
if (csql_column_width_info_list_index >= csql_column_width_info_list_size)
{
temp_list =
(CSQL_COLUMN_WIDTH_INFO *) realloc (csql_column_width_info_list,
sizeof (CSQL_COLUMN_WIDTH_INFO) * (csql_column_width_info_list_size * 2));
if (temp_list == NULL)
{
csql_Error_code = CSQL_ERR_NO_MORE_MEMORY;
return CSQL_FAILURE;
}
csql_column_width_info_list_size *= 2;
csql_column_width_info_list = temp_list;
for (i = csql_column_width_info_list_index; i < csql_column_width_info_list_size; i++)
{
csql_column_width_info_list[i].name = NULL;
csql_column_width_info_list[i].width = 0;
}
}
index = NOT_FOUND;
for (i = 0; i < csql_column_width_info_list_index; i++)
{
if (strcasecmp (column_name, csql_column_width_info_list[i].name) == 0)
{
index = i;
break;
}
}
if (index == NOT_FOUND)
{
index = csql_column_width_info_list_index;
csql_column_width_info_list_index++;
}
if (csql_column_width_info_list[index].name == NULL)
{
temp_name = strdup (column_name);
if (temp_name == NULL)
{
csql_Error_code = CSQL_ERR_NO_MORE_MEMORY;
return CSQL_FAILURE;
}
csql_column_width_info_list[index].name = temp_name;
csql_column_width_info_list[index].width = column_width;
}
else
{
csql_column_width_info_list[index].width = column_width;
}
return CSQL_SUCCESS;
}
/*
* csql_get_column_width() - get column_width related column_name
* return: column_width
* column_name(in): column_name
*/
int
csql_get_column_width (const char *column_name)
{
char name_without_space[1024];
char *result;
int i;
if (column_name == NULL)
{
return 0;
}
if (csql_column_width_info_list == NULL)
{
return 0;
}
strncpy (name_without_space, column_name, sizeof (name_without_space) - 1);
name_without_space[sizeof (name_without_space) - 1] = '\0';
result = trim (name_without_space);
if (result == NULL)
{
return 0;
}
for (i = 0; i < csql_column_width_info_list_index; i++)
{
if (strcasecmp (result, csql_column_width_info_list[i].name) == 0)
{
return csql_column_width_info_list[i].width;
}
}
return 0;
}
/*
* get_column_name_argument() - get column_name and value pointer from argument
* return: int
* column_name(out): column name
* val_str(out): value string in argument
* argument(in): argument
*/
static int
get_column_name_argument (char **column_name, char **val_str, char *argument)
{
char *p;
assert (column_name != NULL && val_str != NULL && argument != NULL);
*column_name = NULL;
*val_str = NULL;
/* argument : "column_name=value" */
*column_name = argument;
p = strrchr (*column_name, '=');
if (p != NULL)
{
*p = '\0';
*val_str = (p + 1);
}
trim (*column_name);
/* max column_name size is 254 */
if (strlen (*column_name) > 254)
{
return CSQL_FAILURE;
}
return CSQL_SUCCESS;
}
/*
* csql_set_trace() - set auto trace on or off
* return:
* arg_str(in):
*/
static void
csql_set_trace (const char *arg_str)
{
char line[128];
char format[128], *p;
if (arg_str != NULL)
{
if (strncmp (arg_str, "on", 2) == 0)
{
prm_set_bool_value (PRM_ID_QUERY_TRACE, true);
csql_Query_trace = true;
if (sscanf (arg_str, "on %127s", format) == 1)
{
p = trim (format);
if (strncmp (p, "text", 4) == 0)
{
prm_set_integer_value (PRM_ID_QUERY_TRACE_FORMAT, QUERY_TRACE_TEXT);
}
else if (strncmp (p, "json", 4) == 0)
{
prm_set_integer_value (PRM_ID_QUERY_TRACE_FORMAT, QUERY_TRACE_JSON);
}
}
}
else if (!strncmp (arg_str, "off", 3))
{
prm_set_bool_value (PRM_ID_QUERY_TRACE, false);
csql_Query_trace = false;
}
}
if (prm_get_bool_value (PRM_ID_QUERY_TRACE) == true)
{
if (prm_get_integer_value (PRM_ID_QUERY_TRACE_FORMAT) == QUERY_TRACE_JSON)
{
snprintf (line, 128, "trace on json");
}
else
{
snprintf (line, 128, "trace on text");
}
}
else
{
snprintf (line, 128, "trace off");
}
csql_append_more_line (0, line);
csql_display_more_lines ("Query Trace");
csql_free_more_lines ();
}
/*
* csql_execute_query() -
* return:
*/
static int
csql_execute_query (const char *stmts)
{
DB_SESSION *session = NULL;
DB_QUERY_RESULT *result = NULL;
int stmt_id = -1;
int db_error = ER_FAILED;
session = db_open_buffer (stmts);
if (session == NULL)
{
goto end;
}
stmt_id = db_compile_statement (session);
if (stmt_id < 0)
{
db_error = stmt_id;
goto end;
}
db_error = db_execute_statement (session, stmt_id, &result);
if (db_error < 0)
{
goto end;
}
db_error = NO_ERROR;
end:
if (result != NULL)
{
db_query_end (result);
}
if (session != NULL)
{
db_close_session (session);
}
return db_error;
}
/*
* csql_display_trace() -
* return:
*/
static void
csql_display_trace (void)
{
const char *stmts = NULL;
DB_SESSION *session = NULL;
int stmt_id, db_error;
DB_QUERY_RESULT *result = NULL;
DB_VALUE trace;
FILE *pf;
int save_row_count;
er_clear ();
db_set_interrupt (0);
db_make_null (&trace);
save_row_count = db_get_row_count_cache ();
stmts = "SHOW TRACE";
session = db_open_buffer (stmts);
if (session == NULL)
{
return;
}
stmt_id = db_compile_statement (session);
if (stmt_id < 0)
{
goto end;
}
db_error = db_execute_statement (session, stmt_id, &result);
if (db_error < 0)
{
goto end;
}
(void) db_query_set_copy_tplvalue (result, 0 /* peek */ );
if (db_query_first_tuple (result) < 0)
{
goto end;
}
if (db_query_get_tuple_value (result, 0, &trace) < 0)
{
goto end;
}
if (DB_VALUE_TYPE (&trace) == DB_TYPE_STRING)
{
pf = csql_popen (csql_Pager_cmd, csql_Output_fp);
fprintf (pf, "\n=== Auto Trace ===\n");
fprintf (pf, "%s\n", db_get_char (&trace));
csql_pclose (pf, csql_Output_fp);
}
end:
if (result != NULL)
{
db_query_end (result);
}
if (session != NULL)
{
db_close_session (session);
}
db_update_row_count_cache (save_row_count);
return;
}
static bool
csql_is_auto_commit_requested (const CSQL_ARGUMENT * csql_arg)
{
assert (csql_arg != NULL);
return csql_arg->auto_commit && prm_get_bool_value (PRM_ID_CSQL_AUTO_COMMIT);
}
static int
get_host_ip (unsigned char *ip_addr)
{
char hostname[CUB_MAXHOSTNAMELEN];
struct hostent *hp;
char *ip;
if (gethostname (hostname, sizeof (hostname)) < 0)
{
return -1;
}
if ((hp = gethostbyname_uhost (hostname)) == NULL)
{
return -1;
}
ip = inet_ntoa (*(struct in_addr *) *hp->h_addr_list);
memcpy (ip_addr, ip, strlen (ip));
return 0;
}
static int
csql_connect (char *argument, CSQL_ARGUMENT * csql_arg)
{
/*dbname can be stored DB name+ @ + remote hostname + \0 */
char buf[DB_MAX_USER_LENGTH + DB_NAME_LEN + CUB_MAXHOSTNAMELEN + 1] = { 0, };
const char *delim = " \n";
char *save_ptr_strtok = NULL;
const char *db_name_ptr = NULL;
char *user_name_ptr = NULL;
char *host_name_ptr = NULL;
char *p = NULL;
const char *err_msg;
CSQL_ARGUMENT csql_new_arg;
csql_Error_code = NO_ERROR;
if (argument == NULL)
{
err_msg = (*csql_get_message) (CSQL_MSG_TOO_FEW_ARGS);
fprintf (csql_Output_fp, "%s\n", err_msg);
return ER_FAILED;
}
memset (&csql_new_arg, 0, sizeof csql_new_arg);
strncpy (buf, argument, sizeof (buf) - 1);
if ((user_name_ptr = strtok_r (buf, delim, &save_ptr_strtok)) == NULL)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
return ER_FAILED;
}
/*find db name following the user name */
db_name_ptr = strtok_r (NULL, delim, &save_ptr_strtok);
if (db_name_ptr == NULL)
{
db_name_ptr = csql_arg->db_name;
}
else
{
if (csql_arg->sa_mode == true)
{
fprintf (csql_Output_fp, "Cannot connect to other DB in the --SA-mode.\n");
return ER_FAILED;
}
}
memcpy (&csql_new_arg, csql_arg, sizeof (CSQL_ARGUMENT));
#if defined(CS_MODE)
memset (boot_Host_connected, 0, sizeof (boot_Host_connected));
#endif /* CS_MODE */
csql_exit_session (0, false);
/*Failed to access other host or db and then access formal db_name */
if (csql_Database_connected)
{
csql_Database_connected = false;
db_shutdown ();
}
er_init ("./csql.err", ER_NEVER_EXIT);
csql_new_arg.passwd = (char *) NULL;
if (db_restart_ex (UTIL_CSQL_NAME, db_name_ptr, user_name_ptr, NULL, NULL, db_get_client_type ()) != NO_ERROR)
{
if (csql_Is_interactive && db_error_code () == ER_AU_INVALID_PASSWORD)
{
p = getpass ((char *) csql_get_message (CSQL_PASSWD_PROMPT_TEXT));
/* try again */
if (db_restart_ex (UTIL_CSQL_NAME, db_name_ptr, user_name_ptr, p, NULL, db_get_client_type ()) != NO_ERROR)
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
csql_check_server_down ();
fprintf (csql_Output_fp, "Warning: current CSQL session is disconnected.\n");
return ER_FAILED;
}
if (p[0] == '\0')
{
csql_new_arg.passwd = (char *) NULL; /* to fit into db_login protocol */
}
else
{
csql_new_arg.passwd = strdup (p);
}
}
else
{
csql_Error_code = CSQL_ERR_SQL_ERROR;
csql_check_server_down ();
fprintf (csql_Output_fp, "Warning: current CSQL session is disconnected.\n");
return ER_FAILED;
}
}
/*If login is success, copy csql_new_arg to csql_arg*/
csql_new_arg.user_name = strdup (user_name_ptr);
strcpy (csql_Db_name, db_name_ptr);
csql_new_arg.db_name = csql_Db_name;
FREE_MEM ((char *) csql_arg->user_name);
FREE_MEM ((char *) csql_arg->passwd);
memcpy (csql_arg, &csql_new_arg, sizeof (CSQL_ARGUMENT));
if (csql_arg->sysadm && au_is_dba_group_member (Au_user))
{
int dummy;
AU_DISABLE (dummy);
}
csql_Database_connected = true;
if (csql_arg->trigger_action_flag == false)
{
db_disable_trigger ();
}
fprintf (csql_Output_fp, "Connected.\n");
/*If connect is success, copy csql_new_arg to csql_arg*/
return NO_ERROR;
}