File cas_cgw_odbc.c¶
File List > broker > cas_cgw_odbc.c
Go to the documentation of this file
/*
*
* 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.
*
*/
/*
* cas_cgw_odbc.c
*/
#ident "$Id$"
#if !defined(WINDOWS)
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif
#include "cas_cgw_odbc.h"
#include "cas_util.h"
#include "cas_log.h"
#include "cas_common.h"
#include "broker_config.h"
#include "broker_cas_cci.h"
#include "cas_cgw_execute.h"
#ifndef WINDOWS
#include <iconv.h>
#endif
#define STRING_MAX_SIZE (16*1024*1024)
#define LOGIN_TIME_OUT (5)
#define NUM_OF_DIGITS(NUMBER) ((int)log10(NUMBER) + 1)
#define DISCONNECTED_STATE (-1)
#define CONNECTED_STATE (0)
#define ODBC_SQLSUCCESS(rc) ((rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO) )
#define SQL_CHK_ERR(h, ht, x) { RETCODE rc = (x);\
if (rc != SQL_SUCCESS) \
{ \
cgw_error_msg ((h), (ht), rc); \
} \
if (rc <= SQL_ERROR) \
{ \
if (db_error_code () == 0) \
{ \
er_set (ER_ERROR_SEVERITY, \
ARG_FILE_LINE, \
ER_CGW_NATIVE_ODBC, \
3, cgw_get_dbms_name (cgw_get_dbms_type ()), -1, "Unknown ODBC Driver Error"); \
} \
goto ODBC_ERROR; \
} \
}
#define UNICODE_CODE_PAGE "UCS-2"
#define UTF8_CODE_PAGE "UTF-8"
#define CONV_STRING_BUF_SIZE (STRING_MAX_SIZE)
#if defined (WINDOWS)
#define CONV_M_TO_W(M, W, LEN) MultiByteToWideChar(CP_UTF8, 0, M, -1, W, LEN)
#else
#define CONV_M_TO_W(M, W, LEN) mbstowcs(W, M, LEN)
#endif
#define CONV_WCS_TO_SQLWCS(string, len) cgw_wchar_to_sqlwchar((string), (len))
typedef struct t_supported_dbms T_SUPPORTED_DBMS;
struct t_supported_dbms
{
const char *dbms_name;
T_DBMS_TYPE dbms_type;
};
static INTL_CODESET client_charset = INTL_CODESET_UTF8;
static char conv_str_buff[CONV_STRING_BUF_SIZE + 1];
static T_SUPPORTED_DBMS supported_dbms_list[] =
{ {"oracle", CAS_CGW_DBMS_ORACLE}, {"mysql", CAS_CGW_DBMS_MYSQL}, {"mariadb", CAS_CGW_DBMS_MARIADB},
{"not supported db", CAS_DBMS_NONE}
};
static int supported_dbms_max_num = sizeof (supported_dbms_list) / sizeof (T_SUPPORTED_DBMS);
static T_DBMS_TYPE curr_dbms_type = CAS_DBMS_NONE;
T_CGW_HANDLE *local_odbc_handle = NULL;
static char connected_db_name[SRV_CON_DBNAME_SIZE] = { 0, };
static char connected_db_user[SRV_CON_DBUSER_SIZE] = { 0, };
static char connected_db_passwd[SRV_CON_DBPASSWD_SIZE] = { 0, };
static void cgw_error_msg (SQLHANDLE hHandle, SQLSMALLINT hType, RETCODE retcode);
static int numeric_string_adjust (SQL_NUMERIC_STRUCT * numeric, char *string);
static int hex_to_numeric_val (SQL_NUMERIC_STRUCT * numeric, char *hexstr);
static int hex_to_char (char c, unsigned char *result);
static int cgw_get_stmt_Info (T_SRV_HANDLE * srv_handle, SQLHSTMT hstmt, T_NET_BUF * net_buf, int stmt_type);
static int cgw_set_bindparam (T_CGW_HANDLE * handle, int bind_num, void *net_type, void *net_value,
ODBC_BIND_INFO * value_list);
static char cgw_odbc_type_to_cci_u_type (SQLLEN odbc_type, SQLLEN is_unsigned_type);
static char cgw_odbc_type_to_charset (SQLLEN odbc_type, SQLLEN is_unsigned_type);
static void cgw_cleanup_handle (T_CGW_HANDLE * handle);
static void cgw_set_charset (char charset);
static char cgw_get_charset (void);
static void cgw_link_server_info (SQLHDBC hdbc);
static bool cgw_is_support_datatype (SQLSMALLINT data_type, SQLLEN type_size);
static int cgw_count_number_of_digits (int num_bits);
static SQLSMALLINT get_c_type (SQLSMALLINT s_type, SQLLEN is_unsigned_type);
static SQLULEN get_datatype_size (SQLSMALLINT s_type, SQLULEN chars, SQLLEN precision, SQLLEN scale);
static char *cgw_datatype_to_string (SQLLEN type);
static char *cgw_utype_to_string (int type);
static int cgw_unicode_to_utf8 (wchar_t * in_src, int in_size, char **out_target, int *out_length);
static int cgw_utf8_to_unicode (const char *in_utf8_str, wchar_t * out_unicode_str, size_t out_unicode_strLen);
static int cgw_conv_mtow (wchar_t * destStr, char *sourStr);
static int cgw_uint32_to_uni16 (uint32_t i, uint16_t * u);
static SQLWCHAR *cgw_wchar_to_sqlwchar (wchar_t * src, size_t len);
static const char *cgw_get_dbms_name (T_DBMS_TYPE db_type);
int
cgw_init (void)
{
SQLRETURN err_code;
/* Step 1: Initialize ODBC handles */
err_code = cgw_init_odbc_handle ();
if (err_code < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
goto ODBC_ERROR;
}
if (SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &local_odbc_handle->henv) == SQL_ERROR)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NOT_ALLOCATE_ENV_HANDLE, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (local_odbc_handle->henv,
SQL_HANDLE_ENV,
err_code = SQLSetEnvAttr (local_odbc_handle->henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0));
/* Step 2: Enable CGW mode in cas_common_lib */
hm_set_cgw_mode (true);
/* Step 3: Register CGW function pointers for cas_common_lib */
hm_set_cgw_free_stmt_func (ux_cgw_free_stmt);
return NO_ERROR;
ODBC_ERROR:
return ER_FAILED;
}
void
cgw_cleanup (void)
{
cgw_cleanup_handle (local_odbc_handle);
}
void
cgw_free_stmt (T_SRV_HANDLE * srv_handle)
{
if (srv_handle->cgw_handle->hstmt)
{
SQLFreeHandle (SQL_HANDLE_STMT, local_odbc_handle->hstmt);
local_odbc_handle->hstmt = NULL;
}
}
int
cgw_get_handle (T_CGW_HANDLE ** cgw_handle)
{
if (local_odbc_handle == NULL || local_odbc_handle->henv == NULL || local_odbc_handle->hdbc == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_HANDLE, 0);
return ER_CGW_INVALID_HANDLE;
}
else
{
*cgw_handle = local_odbc_handle;
}
return NO_ERROR;
}
int
cgw_database_connect (T_DBMS_TYPE dbms_type, const char *connect_url, char *db_name, char *db_user, char *db_passwd)
{
SQLRETURN err_code;
wchar_t wcs_url[(CGW_LINK_URL_MAX_LEN + 1) * sizeof (wchar_t)] = { 0, };
SQLWCHAR *wconn_url = NULL;
SQLWCHAR out_connect_str[(CGW_LINK_URL_MAX_LEN + 1) * sizeof (SQLWCHAR)];
SQLSMALLINT out_connect_str_len;
bool is_conneted = false;
if (cgw_is_database_connected () == CONNECTED_STATE)
{
if (strcmp (db_name, connected_db_name) == 0 && strcmp (db_user, connected_db_user) == 0
&& strcmp (db_passwd, connected_db_passwd) == 0)
{
return NO_ERROR;
}
cgw_database_disconnect ();
}
SQL_CHK_ERR (local_odbc_handle->henv,
SQL_HANDLE_ENV,
err_code = SQLAllocHandle (SQL_HANDLE_DBC, local_odbc_handle->henv, &local_odbc_handle->hdbc));
if (dbms_type == CAS_CGW_DBMS_MYSQL || dbms_type == CAS_CGW_DBMS_MARIADB)
{
SQL_CHK_ERR (local_odbc_handle->hdbc,
SQL_HANDLE_ENV,
err_code =
SQLSetConnectAttrW (local_odbc_handle->hdbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) LOGIN_TIME_OUT,
0));
}
if (connect_url != NULL && strlen (connect_url) > 0)
{
err_code = cgw_conv_mtow ((wchar_t *) wcs_url, (char *) connect_url);
if (err_code < 0)
{
goto ODBC_ERROR;
}
wconn_url = CONV_WCS_TO_SQLWCS (wcs_url, wcslen (wcs_url) + 1);
if (wconn_url == NULL)
{
goto ODBC_ERROR;
}
SQL_CHK_ERR (local_odbc_handle->hdbc,
SQL_HANDLE_DBC,
err_code = SQLDriverConnectW (local_odbc_handle->hdbc,
NULL,
wconn_url,
SQL_NTS,
(SQLWCHAR *) out_connect_str,
(SQLSMALLINT) sizeof (out_connect_str),
&out_connect_str_len, SQL_DRIVER_NOPROMPT));
FREE_MEM (wconn_url);
is_conneted = true;
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NOT_EXIST_LINK_NAME, 0);
goto ODBC_ERROR;
}
cgw_link_server_info (local_odbc_handle->hdbc);
SQL_CHK_ERR (local_odbc_handle->hdbc,
SQL_HANDLE_DBC,
err_code = SQLAllocHandle (SQL_HANDLE_STMT, local_odbc_handle->hdbc, &local_odbc_handle->hstmt));
strncpy (connected_db_name, db_name, sizeof (connected_db_name) - 1);
strncpy (connected_db_user, db_user, sizeof (connected_db_user) - 1);
strncpy (connected_db_passwd, db_passwd, sizeof (connected_db_passwd) - 1);
return NO_ERROR;
ODBC_ERROR:
FREE_MEM (wconn_url);
if (local_odbc_handle->hdbc)
{
if (is_conneted)
{
SQLDisconnect (local_odbc_handle->hdbc);
}
SQLFreeHandle (SQL_HANDLE_DBC, local_odbc_handle->hdbc);
local_odbc_handle->hdbc = NULL;
}
return ER_FAILED;
}
int
cgw_execute (T_SRV_HANDLE * srv_handle, SQLLEN * row_count)
{
SQLRETURN err_code;
if (srv_handle->num_markers > 0)
{
if (srv_handle->cgw_handle->hdbc == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_DBC_HANDLE, 0);
goto ODBC_ERROR;
}
if (srv_handle->cgw_handle->hstmt == NULL)
{
SQL_CHK_ERR (srv_handle->cgw_handle->hdbc,
SQL_HANDLE_DBC, err_code =
SQLAllocHandle (SQL_HANDLE_STMT, local_odbc_handle->hdbc, &srv_handle->cgw_handle->hstmt));
}
}
SQL_CHK_ERR (srv_handle->cgw_handle->hstmt, SQL_HANDLE_STMT, err_code = SQLExecute (srv_handle->cgw_handle->hstmt));
if (err_code < 0)
{
cgw_error_msg (srv_handle->cgw_handle->hstmt, SQL_HANDLE_STMT, err_code);
goto ODBC_ERROR;
}
SQLRowCount (srv_handle->cgw_handle->hstmt, row_count);
srv_handle->is_cursor_open = true;
return NO_ERROR;
ODBC_ERROR:
if (srv_handle->cgw_handle->hstmt)
{
SQLFreeHandle (SQL_HANDLE_STMT, srv_handle->cgw_handle->hstmt);
srv_handle->cgw_handle->hstmt = NULL;
}
return ER_FAILED;
}
int
cgw_row_data (SQLHSTMT hstmt)
{
SQLRETURN err_code;
int no_data = 0;
if (hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
err_code = SQLFetchScroll (hstmt, SQL_FETCH_NEXT, 0);
if (err_code < 0)
{
cgw_error_msg (hstmt, SQL_HANDLE_STMT, err_code);
goto ODBC_ERROR;
}
if (err_code == SQL_NO_DATA_FOUND)
{
no_data = SQL_NO_DATA_FOUND;
}
return no_data;
ODBC_ERROR:
return ER_FAILED;
}
int
cgw_cursor_close (T_SRV_HANDLE * srv_handle)
{
SQLRETURN err_code = 0;
if (srv_handle->cgw_handle->hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (srv_handle->cgw_handle->hstmt, SQL_HANDLE_STMT, err_code =
SQLFreeStmt (srv_handle->cgw_handle->hstmt, SQL_CLOSE));
srv_handle->is_cursor_open = false;
return err_code;
ODBC_ERROR:
return ER_FAILED;
}
int
cgw_copy_tuple (T_COL_BINDER * src_col_binding, T_COL_BINDER * dst_col_binding)
{
SQLRETURN err_code = 0;
T_COL_BINDER *src_binder;
T_COL_BINDER *dst_binder;
if (src_col_binding == NULL || dst_col_binding == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NULL_COL_BINDER, 0);
return ER_FAILED;
}
dst_binder = dst_col_binding;
for (src_binder = src_col_binding; src_binder; src_binder = src_binder->next)
{
memcpy (dst_binder->data_buffer, src_binder->data_buffer, src_binder->col_size);
dst_binder->indPtr = src_binder->indPtr;
dst_binder->is_exist_col_data = true;
dst_binder = dst_binder->next;
}
return err_code;
}
int
cgw_cur_tuple (T_NET_BUF * net_buf, T_COL_BINDER * first_col_binding, int cursor_pos)
{
DB_BIGINT bigint = 0;
T_OBJECT tuple_obj;
T_COL_BINDER *this_col_binding;
int str_len;
SQL_DATE_STRUCT *date;
SQL_TIME_STRUCT *time;
SQL_TIMESTAMP_STRUCT *timestamp;
char *conv_string;
int conv_string_len = 0;
int conv_ret = 0;
net_buf_cp_int (net_buf, cursor_pos, NULL);
memset ((char *) &tuple_obj, 0, sizeof (T_OBJECT));
net_buf_cp_object (net_buf, &tuple_obj);
for (this_col_binding = first_col_binding; this_col_binding; this_col_binding = this_col_binding->next)
{
if (this_col_binding->indPtr == SQL_NULL_DATA)
{
net_buf_cp_int (net_buf, -1, NULL);
}
else
{
str_len = this_col_binding->indPtr;
switch (this_col_binding->col_data_type)
{
case SQL_UNKNOWN_TYPE:
net_buf_cp_int (net_buf, -1, NULL);
break;
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
case SQL_NUMERIC:
case SQL_DECIMAL:
conv_ret =
cgw_unicode_to_utf8 ((wchar_t *) this_col_binding->data_buffer, str_len, &conv_string,
&conv_string_len);
if (conv_ret < 0)
{
net_buf_cp_int (net_buf, -1, NULL);
continue;
}
net_buf_cp_int (net_buf, (int) conv_string_len, NULL);
net_buf_cp_str (net_buf, (char *) conv_string, conv_string_len - 1);
net_buf_cp_byte (net_buf, 0);
break;
case SQL_INTEGER:
if (this_col_binding->col_unsigned_type)
{
net_buf_cp_int (net_buf, NET_SIZE_INT, NULL);
net_buf_cp_int (net_buf, *((unsigned int *) this_col_binding->data_buffer), NULL);
}
else
{
net_buf_cp_int (net_buf, NET_SIZE_INT, NULL);
net_buf_cp_int (net_buf, *((int *) this_col_binding->data_buffer), NULL);
}
break;
case SQL_SMALLINT:
if (this_col_binding->col_unsigned_type)
{
net_buf_cp_int (net_buf, NET_SIZE_SHORT, NULL);
net_buf_cp_short (net_buf, *((unsigned short *) this_col_binding->data_buffer));
}
else
{
net_buf_cp_int (net_buf, NET_SIZE_SHORT, NULL);
net_buf_cp_short (net_buf, *((short *) this_col_binding->data_buffer));
}
break;
case SQL_TINYINT:
if (this_col_binding->col_unsigned_type)
{
net_buf_cp_int (net_buf, NET_SIZE_SHORT, NULL);
net_buf_cp_short (net_buf, *((unsigned char *) this_col_binding->data_buffer));
}
else
{
net_buf_cp_int (net_buf, NET_SIZE_SHORT, NULL);
net_buf_cp_short (net_buf, *((char *) this_col_binding->data_buffer));
}
break;
case SQL_FLOAT:
case SQL_REAL:
net_buf_cp_int (net_buf, NET_SIZE_FLOAT, NULL);
net_buf_cp_float (net_buf, *((float *) this_col_binding->data_buffer));
break;
case SQL_DOUBLE:
net_buf_cp_int (net_buf, NET_SIZE_DOUBLE, NULL);
net_buf_cp_double (net_buf, *((double *) this_col_binding->data_buffer));
break;
case SQL_BIGINT:
net_buf_cp_int (net_buf, NET_SIZE_BIGINT, NULL);
bigint = *((DB_BIGINT *) (this_col_binding->data_buffer));
net_buf_cp_bigint (net_buf, bigint, NULL);
break;
#if (ODBCVER >= 0x0300)
case SQL_DATETIME:
timestamp = (SQL_TIMESTAMP_STRUCT *) (this_col_binding->data_buffer);
net_buf_cp_int (net_buf, NET_SIZE_DATETIME, NULL);
net_buf_cp_short (net_buf, (short) timestamp->year);
net_buf_cp_short (net_buf, (short) timestamp->month);
net_buf_cp_short (net_buf, (short) timestamp->day);
net_buf_cp_short (net_buf, (short) timestamp->hour);
net_buf_cp_short (net_buf, (short) timestamp->minute);
net_buf_cp_short (net_buf, (short) timestamp->second);
if (timestamp->fraction > 0)
{
net_buf_cp_short (net_buf, (short) (timestamp->fraction / 1000000));
}
else
{
net_buf_cp_short (net_buf, 0);
}
break;
#else
case SQL_DATE:
{
date = (SQL_DATE_STRUCT *) (this_col_binding->data_buffer);
net_buf_cp_int (net_buf, NET_SIZE_DATE, NULL);
net_buf_cp_short (net_buf, (short) date->year);
net_buf_cp_short (net_buf, (short) date->month);
net_buf_cp_short (net_buf, (short) date->day);
break;
}
#endif
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
{
date = (SQL_DATE_STRUCT *) (this_col_binding->data_buffer);
net_buf_cp_int (net_buf, NET_SIZE_DATE, NULL);
net_buf_cp_short (net_buf, (short) date->year);
net_buf_cp_short (net_buf, (short) date->month);
net_buf_cp_short (net_buf, (short) date->day);
break;
}
case SQL_TYPE_TIME:
{
time = (SQL_TIME_STRUCT *) (this_col_binding->data_buffer);
net_buf_cp_int (net_buf, NET_SIZE_TIME, NULL);
net_buf_cp_short (net_buf, (short) time->hour);
net_buf_cp_short (net_buf, (short) time->minute);
net_buf_cp_short (net_buf, (short) time->second);
break;
}
case SQL_TYPE_TIMESTAMP:
{
timestamp = (SQL_TIMESTAMP_STRUCT *) (this_col_binding->data_buffer);
net_buf_cp_int (net_buf, NET_SIZE_DATETIME, NULL);
net_buf_cp_short (net_buf, (short) timestamp->year);
net_buf_cp_short (net_buf, (short) timestamp->month);
net_buf_cp_short (net_buf, (short) timestamp->day);
net_buf_cp_short (net_buf, (short) timestamp->hour);
net_buf_cp_short (net_buf, (short) timestamp->minute);
net_buf_cp_short (net_buf, (short) timestamp->second);
if (timestamp->fraction > 0)
{
net_buf_cp_short (net_buf, (short) (timestamp->fraction / 1000000));
}
else
{
net_buf_cp_short (net_buf, 0);
}
break;
}
#if (ODBCVER >= 0x0300)
case SQL_INTERVAL:
net_buf_cp_int (net_buf, -1, NULL);
break;
#else
case SQL_TIME:
{
time = (SQL_TIME_STRUCT *) (this_col_binding->data_buffer);
net_buf_cp_int (net_buf, NET_SIZE_TIME, NULL);
net_buf_cp_short (net_buf, (short) time->hour);
net_buf_cp_short (net_buf, (short) time->minute);
net_buf_cp_short (net_buf, (short) time->second);
break;
}
#endif /* ODBCVER >= 0x0300 */
case SQL_TIMESTAMP:
{
timestamp = (SQL_TIMESTAMP_STRUCT *) (this_col_binding->data_buffer);
net_buf_cp_int (net_buf, NET_SIZE_DATETIME, NULL);
net_buf_cp_short (net_buf, (short) timestamp->year);
net_buf_cp_short (net_buf, (short) timestamp->month);
net_buf_cp_short (net_buf, (short) timestamp->day);
net_buf_cp_short (net_buf, (short) timestamp->hour);
net_buf_cp_short (net_buf, (short) timestamp->minute);
net_buf_cp_short (net_buf, (short) timestamp->second);
if (timestamp->fraction > 0)
{
net_buf_cp_short (net_buf, (short) (timestamp->fraction / 1000000));
}
else
{
net_buf_cp_short (net_buf, 0);
}
break;
}
case SQL_BIT:
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
#if (ODBCVER >= 0x0350)
case SQL_GUID:
net_buf_cp_int (net_buf, -1, NULL);
break;
#endif
default:
net_buf_cp_int (net_buf, -1, NULL);
break;
#endif
}
}
}
return NO_ERROR;
}
int
cgw_get_col_info (SQLHSTMT hstmt, int col_num, T_ODBC_COL_INFO * col_info)
{
SQLRETURN err_code;
SQLSMALLINT col_name_length = 0;
SQLSMALLINT class_name_length = 0;
SQLSMALLINT col_data_type = 0;
SQLLEN col_unsigned_type = 0;
SQLSMALLINT col_decimal_digits = 0;
memset (col_info, 0x0, sizeof (T_ODBC_COL_INFO));
if (hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLDescribeCol (hstmt,
(SQLSMALLINT) col_num,
(SQLCHAR *) col_info->col_name,
sizeof (col_info->col_name),
&col_name_length, &col_data_type, &col_info->precision, &col_decimal_digits,
&col_info->is_not_null));
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLColAttribute (hstmt, col_num, SQL_DESC_SCALE, NULL, 0, NULL, &col_info->scale));
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLColAttribute (hstmt, col_num, SQL_DESC_UNSIGNED, NULL, 0, NULL, &col_unsigned_type));
if (col_data_type == SQL_REAL || col_data_type == SQL_FLOAT || col_data_type == SQL_DOUBLE)
{
int num = cgw_count_number_of_digits (col_info->precision);
if (num < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_PRECISION_VALUE, 1, col_info->col_name);
goto ODBC_ERROR;
}
col_info->precision = num;
}
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLColAttribute (hstmt,
col_num,
SQL_DESC_TABLE_NAME,
col_info->class_name, sizeof (col_info->class_name), &class_name_length,
NULL));
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLColAttribute (hstmt,
col_num,
SQL_DESC_AUTO_UNIQUE_VALUE, NULL, 0, NULL, &col_info->is_auto_increment));
col_info->data_type = cgw_odbc_type_to_cci_u_type (col_data_type, col_unsigned_type);
col_info->charset = cgw_odbc_type_to_charset (col_data_type, col_unsigned_type);
// mariadb has an error in returning the precision value of unsigned bigint (18446744073709551615) as 19.
if (cgw_get_dbms_type () == CAS_CGW_DBMS_MARIADB && col_data_type == SQL_BIGINT && col_unsigned_type)
{
col_info->precision = 20;
col_info->scale = 0;
}
return err_code;
ODBC_ERROR:
return ER_FAILED;
}
static char
cgw_odbc_type_to_cci_u_type (SQLLEN odbc_type, SQLLEN is_unsigned_type)
{
char data_type = CCI_U_TYPE_UNKNOWN;
switch (odbc_type)
{
case SQL_CHAR:
case SQL_WCHAR:
data_type = CCI_U_TYPE_CHAR;
break;
case SQL_NUMERIC:
case SQL_DECIMAL:
data_type = CCI_U_TYPE_NUMERIC;
break;
case SQL_INTEGER:
data_type = (is_unsigned_type) ? CCI_U_TYPE_BIGINT : CCI_U_TYPE_INT;
break;
case SQL_TINYINT:
data_type = CCI_U_TYPE_SHORT;
break;
case SQL_SMALLINT:
data_type = (is_unsigned_type) ? CCI_U_TYPE_INT : CCI_U_TYPE_SHORT;
break;
case SQL_FLOAT:
case SQL_REAL:
data_type = CCI_U_TYPE_FLOAT;
break;
case SQL_DOUBLE:
data_type = CCI_U_TYPE_DOUBLE;
break;
#if (ODBCVER >= 0x0300)
case SQL_DATETIME:
data_type = CCI_U_TYPE_DATETIME;
break;
#else
case SQL_DATE:
data_type = CCI_U_TYPE_DATE;
break;
#endif
#if (ODBCVER >= 0x0300)
case SQL_TYPE_TIMESTAMP:
data_type = CCI_U_TYPE_DATETIME;
break;
case SQL_TYPE_DATE:
data_type = CCI_U_TYPE_DATE;
break;
case SQL_TYPE_TIME:
data_type = CCI_U_TYPE_TIME;
break;
#endif
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
data_type = CCI_U_TYPE_STRING;
break;
#if (ODBCVER >= 0x0300)
case SQL_INTERVAL:
data_type = CCI_U_TYPE_UNKNOWN;
break;
#else /* ODBCVER >= 0x0300 */
case SQL_TIME:
data_type = CCI_U_TYPE_TIME;
break;
#endif
case SQL_TIMESTAMP:
data_type = CCI_U_TYPE_DATETIME;
break;
case SQL_BIGINT:
data_type = (is_unsigned_type) ? CCI_U_TYPE_NUMERIC : CCI_U_TYPE_BIGINT;
break;
#if (ODBCVER >= 0x0350)
case SQL_GUID:
data_type = CCI_U_TYPE_UNKNOWN;
break;
#endif
case SQL_BIT:
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
data_type = CCI_U_TYPE_UNKNOWN;
break;
default:
data_type = CCI_U_TYPE_UNKNOWN;
}
return data_type;
}
static char
cgw_odbc_type_to_charset (SQLLEN odbc_type, SQLLEN is_unsigned_type)
{
char code_set = (char) INTL_CODESET_NONE;
switch (odbc_type)
{
case SQL_CHAR:
case SQL_WCHAR:
code_set = cgw_get_charset ();
break;
case SQL_NUMERIC:
case SQL_DECIMAL:
code_set = INTL_CODESET_ASCII;
break;
case SQL_INTEGER:
code_set = (is_unsigned_type != 0) ? cgw_get_charset () : (char) INTL_CODESET_ASCII;
break;
case SQL_TINYINT:
case SQL_SMALLINT:
code_set = (is_unsigned_type != 0) ? cgw_get_charset () : (char) INTL_CODESET_ASCII;
break;
case SQL_FLOAT:
code_set = INTL_CODESET_ASCII;
break;
case SQL_REAL:
code_set = INTL_CODESET_ASCII;
break;
case SQL_DOUBLE:
code_set = INTL_CODESET_ASCII;
break;
#if (ODBCVER >= 0x0300)
case SQL_DATETIME:
code_set = INTL_CODESET_ASCII;
break;
#else
case SQL_DATE:
code_set = INTL_CODESET_ASCII;
break;
#endif
#if (ODBCVER >= 0x0300)
case SQL_TYPE_TIMESTAMP:
code_set = INTL_CODESET_ASCII;
break;
case SQL_TYPE_DATE:
code_set = INTL_CODESET_ASCII;
break;
case SQL_TYPE_TIME:
code_set = INTL_CODESET_ASCII;
break;
#endif
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
code_set = cgw_get_charset ();
break;
#if (ODBCVER >= 0x0300)
case SQL_INTERVAL:
break;
#else /* ODBCVER >= 0x0300 */
case SQL_TIME:
code_set = INTL_CODESET_ASCII;
break;
#endif
case SQL_TIMESTAMP:
code_set = INTL_CODESET_ASCII;
break;
case SQL_BIGINT:
code_set = (is_unsigned_type != 0) ? cgw_get_charset () : (char) INTL_CODESET_ASCII;
break;
#if (ODBCVER >= 0x0350)
case SQL_GUID:
#endif
case SQL_BIT:
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
code_set = INTL_CODESET_NONE;
break;
default:
code_set = INTL_CODESET_NONE;
}
return code_set;
}
static void
cgw_set_charset (char charset)
{
client_charset = (INTL_CODESET) charset;
}
static char
cgw_get_charset (void)
{
return (char) client_charset;
}
int
cgw_set_execute_info (T_SRV_HANDLE * srv_handle, T_NET_BUF * net_buf, int stmt_type)
{
SQLRETURN err_code;
char cache_reusable = 0;
net_buf_cp_int (net_buf, srv_handle->total_tuple_count, NULL);
net_buf_cp_byte (net_buf, cache_reusable);
net_buf_cp_int (net_buf, (int) srv_handle->num_q_result, NULL);
for (int i = 0; i < srv_handle->num_q_result; i++)
{
err_code = cgw_get_stmt_Info (srv_handle, srv_handle->cgw_handle->hstmt, net_buf, stmt_type);
if (err_code < 0)
{
goto ODBC_ERROR;
}
}
return NO_ERROR;
ODBC_ERROR:
return ER_FAILED;
}
int
cgw_set_commit_mode (SQLHDBC hdbc, bool auto_commit)
{
SQLRETURN err_code = 0;
if (hdbc == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
if (auto_commit)
{
SQL_CHK_ERR (hdbc, SQL_HANDLE_DBC,
err_code = SQLSetConnectAttr (hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER *) SQL_AUTOCOMMIT_ON, SQL_NTS));
}
else
{
SQL_CHK_ERR (hdbc, SQL_HANDLE_DBC,
err_code =
SQLSetConnectAttr (hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER *) SQL_AUTOCOMMIT_OFF, SQL_NTS));
}
return err_code;
ODBC_ERROR:
return ER_FAILED;
}
static int
cgw_get_stmt_Info (T_SRV_HANDLE * srv_handle, SQLHSTMT hstmt, T_NET_BUF * net_buf, int stmt_type)
{
T_OBJECT ins_oid;
CACHE_TIME srv_cache_time;
char statement_type = (char) stmt_type;
if (hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
net_buf_cp_byte (net_buf, statement_type);
net_buf_cp_int (net_buf, srv_handle->total_tuple_count, NULL);
memset (&ins_oid, 0, sizeof (T_OBJECT));
net_buf_cp_object (net_buf, &ins_oid);
CACHE_TIME_RESET (&srv_cache_time);
net_buf_cp_int (net_buf, srv_cache_time.sec, NULL);
net_buf_cp_int (net_buf, srv_cache_time.usec, NULL);
return NO_ERROR;
ODBC_ERROR:
return ER_FAILED;
}
int
cgw_col_bindings (SQLHSTMT hstmt, SQLSMALLINT num_cols, T_COL_BINDER ** col_binding, T_COL_BINDER ** col_binding_buff)
{
SQLRETURN err_code;
SQLSMALLINT col;
T_COL_BINDER *this_col_binding, *last_col_binding = NULL;
T_COL_BINDER *this_col_binding_buff, *last_col_binding_buff = NULL;
SQLSMALLINT col_name_len;
SQLSMALLINT col_data_type, col_decimal_digits, nullable;
SQLULEN col_size, bind_col_size;
SQLLEN precision, scale;
SQLCHAR col_name[COL_NAME_LEN];
SQLLEN col_unsigned_type = 0;
if (hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
for (col = 1; col <= num_cols; col++)
{
this_col_binding = (T_COL_BINDER *) (MALLOC (sizeof (T_COL_BINDER)));
if (!(this_col_binding))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
goto ODBC_ERROR;
}
this_col_binding_buff = (T_COL_BINDER *) (MALLOC (sizeof (T_COL_BINDER)));
if (!(this_col_binding_buff))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
goto ODBC_ERROR;
}
memset (this_col_binding, 0x0, sizeof (T_COL_BINDER));
memset (this_col_binding_buff, 0x0, sizeof (T_COL_BINDER));
if (col == 1)
{
*col_binding = this_col_binding;
*col_binding_buff = this_col_binding_buff;
}
else
{
last_col_binding->next = this_col_binding;
last_col_binding_buff->next = this_col_binding_buff;
}
last_col_binding = this_col_binding;
last_col_binding_buff = this_col_binding_buff;
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLDescribeCol (hstmt,
col,
col_name,
sizeof (col_name),
&col_name_len, &col_data_type, &col_size, &col_decimal_digits,
&nullable));
SQL_CHK_ERR (hstmt, SQL_HANDLE_STMT, SQLColAttribute (hstmt, col, SQL_DESC_SCALE, NULL, 0, NULL, &scale));
SQL_CHK_ERR (hstmt, SQL_HANDLE_STMT, SQLColAttribute (hstmt, col, SQL_DESC_PRECISION, NULL, 0, NULL, &precision));
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLColAttribute (hstmt, col, SQL_DESC_UNSIGNED, NULL, 0, NULL, &col_unsigned_type));
this_col_binding->col_unsigned_type = col_unsigned_type;
this_col_binding_buff->col_unsigned_type = col_unsigned_type;
if (col_unsigned_type)
{
bind_col_size = col_size + 10;
}
else
{
bind_col_size = get_datatype_size (col_data_type, col_size, precision, scale);
}
if (cgw_is_support_datatype (col_data_type, bind_col_size))
{
bind_col_size = bind_col_size * 2;
if (col_unsigned_type)
{
if (col_data_type == SQL_SMALLINT)
{
col_data_type = SQL_INTEGER;
}
else if (col_data_type == SQL_INTEGER)
{
col_data_type = SQL_BIGINT;
}
else if (col_data_type == SQL_BIGINT)
{
col_data_type = SQL_NUMERIC;
}
}
this_col_binding->col_data_type = col_data_type;
this_col_binding->col_size = bind_col_size;
this_col_binding->next = NULL;
this_col_binding_buff->col_data_type = col_data_type;
this_col_binding_buff->col_size = bind_col_size;
this_col_binding_buff->next = NULL;
this_col_binding_buff->is_exist_col_data = false;
this_col_binding->data_buffer = (wchar_t *) MALLOC (bind_col_size);
if (!(this_col_binding->data_buffer))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
goto ODBC_ERROR;
}
this_col_binding_buff->data_buffer = (wchar_t *) MALLOC (bind_col_size);
if (!(this_col_binding_buff->data_buffer))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindCol (hstmt,
col,
get_c_type (col_data_type, col_unsigned_type),
(SQLPOINTER) this_col_binding->data_buffer, bind_col_size,
&this_col_binding->indPtr));
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NOT_SUPPORTED_TYPE, 2,
cgw_datatype_to_string (col_data_type), col_data_type);
goto ODBC_ERROR;
}
}
return NO_ERROR;
ODBC_ERROR:
return ER_FAILED;
}
void
cgw_cleanup_binder (T_COL_BINDER * first_col_binding)
{
T_COL_BINDER *this_col_binding;
while (first_col_binding)
{
this_col_binding = first_col_binding->next;
FREE_MEM (first_col_binding->data_buffer);
FREE_MEM (first_col_binding);
first_col_binding = this_col_binding;
}
}
void
cgw_error_msg (SQLHANDLE hHandle, SQLSMALLINT hType, RETCODE retcode)
{
SQLSMALLINT iRec = 0;
SQLINTEGER iError;
char szMessage[SQL_MAX_MESSAGE_LENGTH + 1];
char szState[SQL_SQLSTATE_SIZE + 1];
er_clear ();
if (retcode == SQL_INVALID_HANDLE)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
return;
}
while (SQLGetDiagRec (hType,
hHandle,
++iRec,
(SQLCHAR *) szState,
&iError,
(SQLCHAR *) szMessage,
(SQLSMALLINT) (sizeof (szMessage) / sizeof (char)), (SQLSMALLINT *) NULL) == SQL_SUCCESS)
{
if (iRec == 1)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NATIVE_ODBC, 3, szState, iError, szMessage);
}
}
}
void
cgw_database_disconnect ()
{
if (local_odbc_handle == NULL)
{
return;
}
if (local_odbc_handle->hstmt)
{
SQLFreeHandle (SQL_HANDLE_STMT, local_odbc_handle->hstmt);
local_odbc_handle->hstmt = NULL;
}
if (local_odbc_handle->hdbc)
{
SQLDisconnect (local_odbc_handle->hdbc);
SQLFreeHandle (SQL_HANDLE_DBC, local_odbc_handle->hdbc);
local_odbc_handle->hdbc = NULL;
}
connected_db_name[0] = '\0';
connected_db_user[0] = '\0';
connected_db_passwd[0] = '\0';
}
static int
cgw_set_bindparam (T_CGW_HANDLE * handle, int bind_num, void *net_type, void *net_value, ODBC_BIND_INFO * value_list)
{
char type;
char src_type = -1;
int err_code = 0;
int data_size;
SQLLEN indPtr = 0;
SQLSMALLINT c_data_type;
SQLSMALLINT sql_bind_type;
if (handle == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_HANDLE, 0);
return ER_CGW_INVALID_HANDLE;
}
if (handle->hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
return ER_CGW_INVALID_STMT_HANDLE;
}
net_arg_get_char (type, net_type);
net_arg_get_size (&data_size, net_value);
// Oracle ODBC does not support the BIGINT type.
// So, change it to Numeric type.
if (curr_dbms_type == CAS_CGW_DBMS_ORACLE && type == CCI_U_TYPE_BIGINT)
{
src_type = type;
type = CCI_U_TYPE_NUMERIC;
}
switch (type)
{
case CCI_U_TYPE_CHAR:
case CCI_U_TYPE_STRING:
{
char *value;
int val_size;
wchar_t *out_string = NULL;
size_t out_length = 0;
net_arg_get_str (&value, &val_size, net_value);
c_data_type = SQL_C_WCHAR;
sql_bind_type = SQL_WVARCHAR;
out_length = (strlen (value) + 1) * sizeof (wchar_t);
out_string = (wchar_t *) malloc (out_length);
if (out_string == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
return ER_INTERFACE_NO_MORE_MEMORY;
}
err_code = cgw_utf8_to_unicode (value, out_string, out_length);
if (err_code < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_SQL_CONV_ERROR, 0);
goto ODBC_ERROR;
}
value_list->wchar_val = out_string;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type, out_length, 0, (SQLWCHAR *) out_string, 0, NULL));
}
break;
case CCI_U_TYPE_NULL:
{
char *value;
int val_size;
net_arg_get_str (&value, &val_size, net_value);
c_data_type = SQL_C_WCHAR;
sql_bind_type = SQL_WVARCHAR;
value_list->cbValue = SQL_NULL_DATA;
value_list->string_val = value;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type, val_size + 1, 0, value_list->string_val, 0,
&value_list->cbValue));
}
break;
case CCI_U_TYPE_NUMERIC:
{
if (curr_dbms_type == CAS_CGW_DBMS_MARIADB)
{
char *value = NULL;
int val_size = 0;
net_arg_get_str (&value, &val_size, net_value);
c_data_type = SQL_C_CHAR;
sql_bind_type = SQL_CHAR;
value_list->string_val = value;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type, val_size + 1, 0, value_list->string_val, 0, NULL));
}
else
{
char *value = NULL, *p = NULL;
int val_size = 0;
size_t precision = 0, scale = 0;
char num_str[64] = { 0, };
char tmp[64] = { 0, };
SQLHDESC hdesc = NULL;
DB_BIGINT bi_val;
SQL_CHK_ERR (handle->hdbc, SQL_HANDLE_DBC, err_code =
SQLAllocHandle (SQL_HANDLE_DESC, handle->hdbc, &hdesc));
memset (&value_list->ns_val, 0x00, sizeof (SQL_NUMERIC_STRUCT));
if (src_type == CCI_U_TYPE_BIGINT)
{
net_arg_get_bigint (&bi_val, net_value);
snprintf (tmp, sizeof (tmp), "%" PRId64, bi_val);
}
else
{
net_arg_get_str (&value, &val_size, net_value);
if (value != NULL)
{
strcpy (tmp, value);
}
tmp[val_size] = '\0';
}
ut_trim (tmp);
precision = strlen (tmp);
p = strchr (tmp, '.');
if (p == NULL)
{
scale = 0;
}
else
{
scale = strlen (p + 1);
precision--;
}
if (tmp[0] == '-')
{
precision--;
value_list->ns_val.sign = MINUS;
}
else
{
value_list->ns_val.sign = PLUS;
}
value_list->ns_val.precision = precision;
value_list->ns_val.scale = scale;
if (value_list->ns_val.sign == MINUS)
{
strcpy (num_str, &tmp[1]);
}
else
{
strcpy (num_str, &tmp[0]);
}
err_code = numeric_string_adjust (&value_list->ns_val, num_str);
if (err_code < 0)
{
goto ODBC_ERROR;
}
c_data_type = SQL_C_NUMERIC;
sql_bind_type = SQL_DECIMAL;
indPtr = sizeof (value_list->ns_val);
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type,
value_list->ns_val.precision,
value_list->ns_val.scale, &value_list->ns_val, 0,
(SQLLEN *) & indPtr));
SQL_CHK_ERR (hdesc,
SQL_HANDLE_DESC,
err_code =
SQLSetDescField (hdesc, bind_num, SQL_DESC_TYPE, (SQLPOINTER) SQL_C_NUMERIC, SQL_NTS));
SQL_CHK_ERR (hdesc,
SQL_HANDLE_DESC,
err_code =
SQLSetDescField (hdesc, bind_num, SQL_DESC_PRECISION,
(SQLPOINTER) (uintptr_t) value_list->ns_val.precision, 0));
SQL_CHK_ERR (hdesc,
SQL_HANDLE_DESC,
err_code =
SQLSetDescField (hdesc, bind_num, SQL_DESC_SCALE,
(SQLPOINTER) (uintptr_t) value_list->ns_val.scale, 0));
SQL_CHK_ERR (hdesc,
SQL_HANDLE_DESC,
err_code =
SQLSetDescField (hdesc, bind_num, SQL_DESC_DATA_PTR, (SQLPOINTER) & value_list->ns_val, 0));
SQLFreeHandle (SQL_HANDLE_DESC, hdesc);
}
}
break;
case CCI_U_TYPE_BIGINT:
case CCI_U_TYPE_UBIGINT:
{
DB_BIGINT bi_val;
net_arg_get_bigint (&bi_val, net_value);
c_data_type = SQL_C_SBIGINT;
sql_bind_type = SQL_BIGINT;
value_list->bigint_val = bi_val;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type, sql_bind_type, 0, 0, &value_list->bigint_val, 0,
&indPtr));
}
break;
case CCI_U_TYPE_INT:
case CCI_U_TYPE_UINT:
{
int i_val;
net_arg_get_int (&i_val, net_value);
c_data_type = SQL_C_LONG;
sql_bind_type = SQL_INTEGER;
value_list->integer_val = i_val;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type, sql_bind_type, 0, 0, &value_list->integer_val, 0,
&indPtr));
}
break;
case CCI_U_TYPE_SHORT:
case CCI_U_TYPE_USHORT:
{
short s_val;
net_arg_get_short (&s_val, net_value);
c_data_type = SQL_C_SHORT;
sql_bind_type = SQL_SMALLINT;
value_list->smallInt_val = s_val;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type, sql_bind_type, 0, 0, &value_list->smallInt_val, 0,
&indPtr));
}
break;
case CCI_U_TYPE_FLOAT:
{
float f_val;
net_arg_get_float (&f_val, net_value);
c_data_type = SQL_C_FLOAT;
sql_bind_type = SQL_REAL;
value_list->real_val = f_val;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type, sql_bind_type, 0, 0, &value_list->real_val, 0, &indPtr));
}
break;
case CCI_U_TYPE_DOUBLE:
{
double d_val;
net_arg_get_double (&d_val, net_value);
c_data_type = SQL_C_DOUBLE;
sql_bind_type = SQL_DOUBLE;
value_list->double_val = d_val;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type, sql_bind_type, 0, 0, &value_list->double_val, 0,
&indPtr));
}
break;
case CCI_U_TYPE_DATE:
{
short month, day, year;
net_arg_get_date (&year, &month, &day, net_value);
c_data_type = SQL_C_TYPE_DATE;
sql_bind_type = SQL_TYPE_DATE;
value_list->ds_val.year = year;
value_list->ds_val.month = month;
value_list->ds_val.day = day;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type,
sizeof (SQL_DATE_STRUCT), 0, &value_list->ds_val, 0, &indPtr));
}
break;
case CCI_U_TYPE_TIME:
{
short hh, mm, ss;
net_arg_get_time (&hh, &mm, &ss, net_value);
c_data_type = SQL_C_TYPE_TIME;
sql_bind_type = SQL_TYPE_TIME;
value_list->ts_val.hour = hh;
value_list->ts_val.minute = mm;
value_list->ts_val.second = ss;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type,
sizeof (SQL_TIME_STRUCT), 0, &value_list->ts_val, 0, &indPtr));
}
break;
case CCI_U_TYPE_TIMESTAMP:
{
short yr, mon, day, hh, mm, ss;
DB_DATE date;
DB_TIME time;
DB_TIMESTAMP ts;
net_arg_get_timestamp (&yr, &mon, &day, &hh, &mm, &ss, net_value);
err_code = db_date_encode (&date, mon, day, yr);
if (err_code != NO_ERROR)
{
break;
}
err_code = db_time_encode (&time, hh, mm, ss);
if (err_code != NO_ERROR)
{
break;
}
err_code = db_timestamp_encode_ses (&date, &time, &ts, NULL);
if (err_code != NO_ERROR)
{
break;
}
c_data_type = SQL_C_CHAR;
sql_bind_type = SQL_TYPE_TIMESTAMP;
sprintf (value_list->time_stemp_str_val, "%d-%d-%d %d:%d:%d", yr, mon, day, hh, mm, ss);
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type,
0,
0,
(SQLPOINTER) (&value_list->time_stemp_str_val),
sizeof (value_list->time_stemp_str_val), NULL));
}
break;
case CCI_U_TYPE_DATETIME:
{
short yr, mon, day, hh, mm, ss, ms;
DB_DATETIME dt;
net_arg_get_datetime (&yr, &mon, &day, &hh, &mm, &ss, &ms, net_value);
err_code = db_datetime_encode (&dt, mon, day, yr, hh, mm, ss, ms);
if (err_code != NO_ERROR)
{
break;
}
if (curr_dbms_type == CAS_CGW_DBMS_MYSQL || curr_dbms_type == CAS_CGW_DBMS_MARIADB)
{
c_data_type = SQL_C_CHAR;
sql_bind_type = SQL_TYPE_TIMESTAMP;
sprintf (value_list->time_stemp_str_val, "%d-%d-%d %d:%d:%d.%d", yr, mon, day, hh, mm, ss, ms);
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type,
0,
0,
(SQLPOINTER) (&value_list->time_stemp_str_val),
sizeof (value_list->time_stemp_str_val), NULL));
}
else if (curr_dbms_type == CAS_CGW_DBMS_ORACLE)
{
c_data_type = SQL_C_TYPE_TIMESTAMP;
sql_bind_type = SQL_TYPE_TIMESTAMP;
value_list->tss_val.year = yr;
value_list->tss_val.month = mon;
value_list->tss_val.day = day;
value_list->tss_val.hour = hh;
value_list->tss_val.minute = mm;
value_list->tss_val.second = ss;
value_list->tss_val.fraction = ms;
SQL_CHK_ERR (handle->hstmt,
SQL_HANDLE_STMT,
err_code = SQLBindParameter (handle->hstmt,
bind_num,
SQL_PARAM_INPUT,
c_data_type,
sql_bind_type,
0,
0,
(SQLPOINTER) (&value_list->tss_val),
sizeof (value_list->tss_val), NULL));
}
else
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NOT_SUPPORTED_DBMS, 0);
return ER_CGW_NOT_SUPPORTED_DBMS;
}
}
break;
/* Not Support Type */
case CCI_U_TYPE_BIT:
case CCI_U_TYPE_VARBIT:
case CCI_U_TYPE_MONETARY:
case CCI_U_TYPE_SET:
case CCI_U_TYPE_MULTISET:
case CCI_U_TYPE_SEQUENCE:
case CCI_U_TYPE_OBJECT:
case CCI_U_TYPE_BLOB:
case CCI_U_TYPE_CLOB:
case CCI_U_TYPE_JSON:
case CCI_U_TYPE_ENUM:
case CCI_U_TYPE_DATETIMELTZ:
case CCI_U_TYPE_DATETIMETZ:
case CCI_U_TYPE_TIMESTAMPTZ:
case CCI_U_TYPE_TIMESTAMPLTZ:
default:
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NOT_SUPPORTED_TYPE, 2, cgw_utype_to_string (type), type);
return ER_CGW_NOT_SUPPORTED_TYPE;
}
}
if (err_code < 0)
{
return ERROR_INFO_SET (err_code, DBMS_ERROR_INDICATOR);
}
return data_size;
ODBC_ERROR:
return ER_FAILED;
}
int
cgw_sql_prepare (SQLCHAR * sql_stmt)
{
SQLRETURN err_code;
wchar_t *out_string = NULL;
char *in_string = NULL;
size_t out_length = 0;
in_string = (char *) sql_stmt;
if (local_odbc_handle->hstmt == NULL)
{
SQL_CHK_ERR (local_odbc_handle->hdbc,
SQL_HANDLE_DBC,
err_code = SQLAllocHandle (SQL_HANDLE_STMT, local_odbc_handle->hdbc, &local_odbc_handle->hstmt));
}
out_length = (strlen (in_string) + 1) * sizeof (wchar_t);
out_string = (wchar_t *) malloc (out_length);
if (out_string == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
return ER_INTERFACE_NO_MORE_MEMORY;
}
memset (out_string, 0x0, out_length);
err_code = cgw_utf8_to_unicode (in_string, out_string, out_length);
if (err_code < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_SQL_CONV_ERROR, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (local_odbc_handle->hstmt, SQL_HANDLE_STMT, err_code =
SQLPrepareW (local_odbc_handle->hstmt, (SQLWCHAR *) out_string, SQL_NTS));
FREE_MEM (out_string);
return (int) err_code;
ODBC_ERROR:
FREE_MEM (out_string);
return ER_FAILED;
}
int
cgw_get_num_cols (SQLHSTMT hstmt, SQLSMALLINT * num_cols)
{
SQLRETURN err_code;
if (hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (hstmt, SQL_HANDLE_STMT, err_code = SQLNumResultCols (hstmt, num_cols));
if (*num_cols == 0)
{
SQL_CHK_ERR (hstmt, SQL_HANDLE_STMT, err_code = SQLExecute (hstmt));
SQL_CHK_ERR (hstmt, SQL_HANDLE_STMT, err_code = SQLNumResultCols (hstmt, num_cols));
}
return (int) err_code;
ODBC_ERROR:
return ER_FAILED;
}
int
cgw_make_bind_value (T_CGW_HANDLE * handle, int num_bind, int argc, void **argv, ODBC_BIND_INFO ** ret_val)
{
int i, type_idx, val_idx;
int err_code;
ODBC_BIND_INFO *bind_value_list = NULL;
*ret_val = NULL;
if (handle == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_HANDLE, 0);
return ER_CGW_INVALID_HANDLE;
}
if (num_bind != (argc / 2))
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_NUM_BIND, 0);
return ER_CGW_NUM_BIND;
}
bind_value_list = (ODBC_BIND_INFO *) MALLOC (sizeof (ODBC_BIND_INFO) * num_bind);
if (bind_value_list == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INTERFACE_NO_MORE_MEMORY, 0);
return ER_INTERFACE_NO_MORE_MEMORY;
}
memset (bind_value_list, 0, sizeof (ODBC_BIND_INFO) * num_bind);
for (i = 0; i < num_bind; i++)
{
type_idx = 2 * i;
val_idx = 2 * i + 1;
err_code = cgw_set_bindparam (handle, i + 1, argv[type_idx], argv[val_idx], &(bind_value_list[i]));
if (err_code < 0)
{
for (int j = 0; j < i; j++)
{
if (bind_value_list[j].wchar_val)
{
FREE_MEM (bind_value_list[j].wchar_val);
}
}
FREE_MEM (bind_value_list);
return err_code;
}
}
*ret_val = bind_value_list;
return NO_ERROR;
}
int
cgw_is_database_connected ()
{
SQLRETURN err_code;
SQLINTEGER is_conn_dead = DISCONNECTED_STATE;
if (local_odbc_handle == NULL || local_odbc_handle->hdbc == NULL)
{
return DISCONNECTED_STATE;
}
err_code =
SQLGetConnectAttr (local_odbc_handle->hdbc, SQL_ATTR_CONNECTION_DEAD, (SQLPOINTER) & is_conn_dead, SQL_IS_INTEGER,
0);
if (err_code < 0)
{
return DISCONNECTED_STATE;
}
return (is_conn_dead == SQL_CD_FALSE) ? CONNECTED_STATE : DISCONNECTED_STATE;
}
static int
numeric_string_adjust (SQL_NUMERIC_STRUCT * numeric, char *string)
{
char *pt, *pt2;
char hexstr[SQL_MAX_NUMERIC_LEN + 1] = { 0 };
char num_val[DECIMAL_DIGIT_MAX_LEN + 1] = { 0 };
short i;
int num_add_zero;
UINT64 number = 0;
char *endptr = NULL;
int error;
pt = string;
pt2 = strchr (pt, '.');
if (pt2 != NULL)
{
strncpy (num_val, pt, pt2 - pt);
num_val[pt2 - pt] = '\0';
++pt2;
strcat (num_val, pt2);
num_add_zero = numeric->scale - strlen (pt2);
if (num_add_zero < 0)
{
num_val[strlen (num_val) + num_add_zero] = '\0';
}
else
{
// add additional '0' for scale
for (pt = num_val + strlen (num_val), i = 1; i <= num_add_zero; ++pt, ++i)
{
*pt = '0';
}
*pt = '\0';
}
}
else
{
strcpy (num_val, pt);
}
error = str_to_uint64 (&number, &endptr, num_val, 10);
if (error < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_NUMERIC_VALUE, 0);
return ER_CGW_INVALID_NUMERIC_VALUE;
}
sprintf (hexstr, "%" PRIX64, number);
error = hex_to_numeric_val (numeric, hexstr);
if (error < 0)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_NUMERIC_VALUE, 0);
return ER_CGW_INVALID_NUMERIC_VALUE;
}
return NO_ERROR;
}
static int
hex_to_numeric_val (SQL_NUMERIC_STRUCT * numeric, char *hexstr)
{
size_t slen = 0;
size_t loop = 0;
int error;
unsigned char ms_val = 0, ls_val = 0;
slen = strlen (hexstr);
if (slen < 1)
{
return ER_FAILED;
}
loop = (slen % 2) + (slen / 2);
for (size_t i = 0; i < loop; i++)
{
if (slen == 1)
{
error = hex_to_char (*(hexstr), &ms_val);
if (error < 0)
{
return ER_FAILED;
}
numeric->val[i] = ms_val;
break;
}
else
{
error = hex_to_char (*(hexstr + (slen - 2)), &ms_val);
if (error < 0)
{
return ER_FAILED;
}
error = hex_to_char (*(hexstr + slen - 1), &ls_val);
if (error < 0)
{
return ER_FAILED;
}
numeric->val[i] = (ms_val << 4) | (ls_val);
}
slen -= 2;
}
return NO_ERROR;
}
static int
hex_to_char (char c, unsigned char *result)
{
int error = NO_ERROR;
if (c >= '0' && c <= '9')
*result = c - '0';
else if (c >= 'a' && c <= 'f')
*result = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
*result = c - 'A' + 10;
else
error = ER_FAILED;
return error;
}
static void
cgw_cleanup_handle (T_CGW_HANDLE * handle)
{
if (handle == NULL)
{
return;
}
if (handle->hstmt)
{
SQLFreeHandle (SQL_HANDLE_STMT, handle->hstmt);
handle->hstmt = NULL;
}
if (handle->hdbc)
{
SQLDisconnect (handle->hdbc);
SQLFreeHandle (SQL_HANDLE_DBC, handle->hdbc);
handle->hdbc = NULL;
}
if (handle->henv)
{
SQLFreeHandle (SQL_HANDLE_ENV, handle->henv);
handle->henv = NULL;
}
FREE_MEM (handle);
local_odbc_handle = NULL;
}
int
cgw_endtran (SQLHDBC hdbc, int tran_type)
{
SQLRETURN err_code;
if (hdbc == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_DBC_HANDLE, 0);
goto ODBC_ERROR;
}
if (tran_type == CCI_TRAN_COMMIT)
{
SQL_CHK_ERR (hdbc, SQL_HANDLE_DBC, err_code = SQLEndTran (SQL_HANDLE_DBC, hdbc, SQL_COMMIT));
}
else
{
SQL_CHK_ERR (hdbc, SQL_HANDLE_DBC, err_code = SQLEndTran (SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK));
}
return err_code;
ODBC_ERROR:
return ER_FAILED;
}
int
cgw_init_odbc_handle (void)
{
local_odbc_handle = (T_CGW_HANDLE *) MALLOC (sizeof (T_CGW_HANDLE));
if (local_odbc_handle == NULL)
{
return ER_FAILED;
}
memset (local_odbc_handle, 0x0, sizeof (T_CGW_HANDLE));
return NO_ERROR;
}
int
cgw_get_driver_info (SQLHDBC hdbc, SQLUSMALLINT info_type, void *driver_info, SQLSMALLINT size)
{
SQLRETURN err_code;
SQLSMALLINT len;
if (hdbc == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_DBC_HANDLE, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (hdbc, SQL_HANDLE_DBC, err_code = SQLGetInfo (hdbc, info_type, driver_info, size, &len));
return NO_ERROR;
ODBC_ERROR:
return ER_FAILED;
}
SQLULEN
get_datatype_size (SQLSMALLINT s_type, SQLULEN chars, SQLLEN precision, SQLLEN scale)
{
switch (s_type)
{
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
chars++;
break;
#if (ODBCVER >= 0x0350)
case SQL_GUID:
#endif
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
if (precision > scale)
{
chars += 3; // sign symbol and decimal symbol
}
else
{
chars = scale + 3; // if the scale is larger. ex)number(4, 6)
}
break;
case SQL_BIT:
chars = sizeof (unsigned char);
break;
case SQL_TINYINT:
chars = sizeof (char);
break;
case SQL_SMALLINT:
chars = sizeof (short);
break;
case SQL_INTEGER:
chars = sizeof (int);
break;
case SQL_BIGINT:
chars = sizeof (INT64);
break;
case SQL_REAL:
case SQL_FLOAT:
chars = sizeof (float);
break;
case SQL_DOUBLE:
chars = sizeof (double);
break;
#if (ODBCVER >= 0x0300)
case SQL_DATETIME:
chars = sizeof (TIMESTAMP_STRUCT);
break;
#else
case SQL_DATE:
chars = sizeof (DATE_STRUCT);
break;
#endif
case SQL_TIME:
chars = sizeof (TIME_STRUCT);
break;
case SQL_TIMESTAMP:
chars = sizeof (TIMESTAMP_STRUCT);
break;
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
chars = sizeof (SQL_DATE_STRUCT);
break;
case SQL_TYPE_TIME:
chars = sizeof (TIME_STRUCT);
break;
case SQL_TYPE_TIMESTAMP:
chars = sizeof (TIMESTAMP_STRUCT);
break;
case SQL_INTERVAL_YEAR:
case SQL_INTERVAL_MONTH:
case SQL_INTERVAL_YEAR_TO_MONTH:
case SQL_INTERVAL_DAY:
case SQL_INTERVAL_HOUR:
case SQL_INTERVAL_MINUTE:
case SQL_INTERVAL_SECOND:
case SQL_INTERVAL_DAY_TO_HOUR:
case SQL_INTERVAL_DAY_TO_MINUTE:
case SQL_INTERVAL_DAY_TO_SECOND:
case SQL_INTERVAL_HOUR_TO_MINUTE:
case SQL_INTERVAL_HOUR_TO_SECOND:
case SQL_INTERVAL_MINUTE_TO_SECOND:
chars = sizeof (SQL_INTERVAL_STRUCT);
break;
#endif
default:
chars = 0;
break;
}
return chars;
}
static SQLSMALLINT
get_c_type (SQLSMALLINT s_type, SQLLEN is_unsigned_type)
{
SQLSMALLINT c_type;
switch (s_type)
{
#if (ODBCVER >= 0x0350)
case SQL_GUID:
#endif
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
c_type = SQL_C_WCHAR;
break;
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
c_type = SQL_C_WCHAR;
break;
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
c_type = SQL_C_BINARY;
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
c_type = SQL_C_WCHAR;
break;
case SQL_BIT:
c_type = SQL_C_BIT;
break;
case SQL_TINYINT:
c_type = (is_unsigned_type) ? SQL_C_UTINYINT : SQL_C_TINYINT;
break;
case SQL_SMALLINT:
c_type = (is_unsigned_type) ? SQL_C_USHORT : SQL_C_SHORT;
break;
case SQL_INTEGER:
c_type = (is_unsigned_type) ? SQL_C_ULONG : SQL_C_LONG;
break;
case SQL_BIGINT:
c_type = (is_unsigned_type) ? SQL_C_UBIGINT : SQL_C_SBIGINT;
break;
case SQL_REAL:
case SQL_FLOAT:
c_type = SQL_C_FLOAT;
break;
case SQL_DOUBLE:
c_type = SQL_C_DOUBLE;
break;
case SQL_DATE:
c_type = SQL_C_DATE;
break;
case SQL_TIME:
c_type = SQL_C_TIME;
break;
case SQL_TIMESTAMP:
c_type = SQL_C_TIMESTAMP;
break;
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
c_type = SQL_C_TYPE_DATE;
break;
case SQL_TYPE_TIME:
c_type = SQL_C_TYPE_TIME;
break;
case SQL_TYPE_TIMESTAMP:
c_type = SQL_C_TYPE_TIMESTAMP;
break;
case SQL_INTERVAL_YEAR:
c_type = SQL_C_INTERVAL_YEAR;
break;
case SQL_INTERVAL_MONTH:
c_type = SQL_C_INTERVAL_MONTH;
break;
case SQL_INTERVAL_YEAR_TO_MONTH:
c_type = SQL_C_INTERVAL_YEAR_TO_MONTH;
break;
case SQL_INTERVAL_DAY:
c_type = SQL_C_INTERVAL_DAY;
break;
case SQL_INTERVAL_HOUR:
c_type = SQL_C_INTERVAL_HOUR;
break;
case SQL_INTERVAL_MINUTE:
c_type = SQL_C_INTERVAL_MINUTE;
break;
case SQL_INTERVAL_SECOND:
c_type = SQL_C_INTERVAL_SECOND;
break;
case SQL_INTERVAL_DAY_TO_HOUR:
c_type = SQL_C_INTERVAL_DAY_TO_HOUR;
break;
case SQL_INTERVAL_DAY_TO_MINUTE:
c_type = SQL_C_INTERVAL_DAY_TO_MINUTE;
break;
case SQL_INTERVAL_DAY_TO_SECOND:
c_type = SQL_C_INTERVAL_DAY_TO_SECOND;
break;
case SQL_INTERVAL_HOUR_TO_MINUTE:
c_type = SQL_C_INTERVAL_HOUR_TO_MINUTE;
break;
case SQL_INTERVAL_HOUR_TO_SECOND:
c_type = SQL_C_INTERVAL_HOUR_TO_SECOND;
break;
case SQL_INTERVAL_MINUTE_TO_SECOND:
c_type = SQL_C_INTERVAL_MINUTE_TO_SECOND;
break;
#endif
default:
c_type = SQL_UNKNOWN_TYPE;
break;
}
return c_type;
}
int
cgw_set_stmt_attr (SQLHSTMT hstmt, SQLINTEGER attr, SQLPOINTER val, SQLINTEGER len)
{
SQLRETURN err_code;
if (hstmt == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_STMT_HANDLE, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (hstmt, SQL_HANDLE_STMT, err_code = SQLSetStmtAttr (hstmt, attr, val, len));
return err_code;
ODBC_ERROR:
return ER_FAILED;
}
static void
cgw_link_server_info (SQLHDBC hdbc)
{
SQLCHAR dbms_name[CGW_LINK_SERVER_NAME_LEN] = { 0, };
SQLCHAR dbms_ver[CGW_LINK_SERVER_NAME_LEN] = { 0, };
SQLCHAR driver_name[CGW_LINK_SERVER_NAME_LEN] = { 0, };
SQLCHAR driver_version[CGW_LINK_SERVER_NAME_LEN] = { 0, };
SQLCHAR odbc_version[CGW_LINK_SERVER_NAME_LEN] = { 0, };
if (hdbc != NULL)
{
cas_log_write_and_end (0, false, "Link Server Info.");
cgw_get_driver_info (hdbc, SQL_DBMS_NAME, dbms_name, sizeof (dbms_name));
cas_log_write_and_end (0, false, "DBMS Name : %s", dbms_name);
cgw_get_driver_info (hdbc, SQL_DBMS_VER, dbms_ver, sizeof (dbms_ver));
cas_log_write_and_end (0, false, "DBMS Version : %s", dbms_ver);
cgw_get_driver_info (hdbc, SQL_DRIVER_NAME, driver_name, sizeof (driver_name));
cas_log_write_and_end (0, false, "Driver Name : %s", driver_name);
cgw_get_driver_info (hdbc, SQL_DRIVER_VER, driver_version, sizeof (driver_version));
cas_log_write_and_end (0, false, "Driver Version : %s", driver_version);
cgw_get_driver_info (hdbc, SQL_ODBC_VER, odbc_version, sizeof (odbc_version));
cas_log_write_and_end (0, false, "ODBC Version : %s", odbc_version);
}
}
static bool
cgw_is_support_datatype (SQLSMALLINT data_type, SQLLEN type_size)
{
bool support_data_type = true;
switch (data_type)
{
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_LONGVARCHAR:
case SQL_WCHAR:
case SQL_WVARCHAR:
case SQL_WLONGVARCHAR:
case SQL_DECIMAL:
case SQL_REAL:
case SQL_NUMERIC:
case SQL_INTEGER:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_FLOAT:
case SQL_DOUBLE:
case SQL_BIGINT:
#if (ODBCVER >= 0x0300)
case SQL_DATETIME:
#else
case SQL_DATE:
#endif
case SQL_TIMESTAMP:
#if (ODBCVER >= 0x0300)
case SQL_TYPE_TIMESTAMP:
case SQL_TYPE_DATE:
case SQL_TYPE_TIME:
#endif
if ((data_type == SQL_LONGVARCHAR || data_type == SQL_WLONGVARCHAR) && type_size > STRING_MAX_SIZE)
{
support_data_type = false;
}
break;
case SQL_VARBINARY:
case SQL_BINARY:
case SQL_BIT:
case SQL_UNKNOWN_TYPE:
case SQL_LONGVARBINARY:
#if (ODBCVER >= 0x0350)
case SQL_GUID:
#endif
support_data_type = false;
break;
default:
support_data_type = false;
break;
}
return support_data_type;
}
static int
cgw_count_number_of_digits (int num_bits)
{
if (num_bits < 0 || num_bits > 64)
{
return ER_FAILED;
}
return (num_bits == 0) ? 0 : NUM_OF_DIGITS (pow (2, num_bits) - 1);
}
T_DBMS_TYPE
cgw_is_supported_dbms (char *dbms)
{
if (dbms == NULL)
return CAS_DBMS_NONE;
ut_tolower (dbms);
for (int i = 0; i < supported_dbms_max_num; i++)
{
if (strcmp (dbms, supported_dbms_list[i].dbms_name) == 0)
{
return supported_dbms_list[i].dbms_type;
}
}
return CAS_DBMS_NONE;
}
int
cgw_get_stmt_handle (SQLHDBC hdbc, SQLHSTMT * stmt)
{
if (hdbc == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CGW_INVALID_DBC_HANDLE, 0);
goto ODBC_ERROR;
}
SQL_CHK_ERR (hdbc, SQL_HANDLE_DBC, SQLAllocHandle (SQL_HANDLE_STMT, hdbc, stmt));
return NO_ERROR;
ODBC_ERROR:
return ER_FAILED;
}
void
cgw_set_dbms_type (T_DBMS_TYPE dbms_type)
{
curr_dbms_type = dbms_type;
}
T_DBMS_TYPE
cgw_get_dbms_type ()
{
return curr_dbms_type;
}
static char *
cgw_datatype_to_string (SQLLEN type)
{
switch (type)
{
case SQL_UNKNOWN_TYPE:
return (char *) "SQL_UNKNOWN_TYPE";
break;
case SQL_CHAR:
return (char *) "SQL_CHAR";
break;
case SQL_NUMERIC:
return (char *) "SQL_NUMERIC";
break;
case SQL_DECIMAL:
return (char *) "SQL_DECIMAL";
break;
case SQL_INTEGER:
return (char *) "SQL_INTEGER";
break;
case SQL_SMALLINT:
return (char *) "SQL_SMALLINT";
break;
case SQL_FLOAT:
return (char *) "SQL_FLOAT";
break;
case SQL_REAL:
return (char *) "SQL_REAL";
break;
case SQL_DOUBLE:
return (char *) "SQL_DOUBLE";
break;
#if (ODBCVER >= 0x0300)
case SQL_DATETIME:
return (char *) "SQL_DATETIME";
break;
#else
case SQL_DATE:
return (char *) "SQL_DATE";
break;
#endif
case SQL_VARCHAR:
return (char *) "SQL_VARCHAR";
break;
#if (ODBCVER >= 0x0300)
case SQL_TYPE_DATE:
return (char *) "SQL_TYPE_DATE";
break;
case SQL_TYPE_TIME:
return (char *) "SQL_TYPE_TIME";
break;
case SQL_TYPE_TIMESTAMP:
return (char *) "SQL_TYPE_TIMESTAMP";
break;
#endif
#if (ODBCVER >= 0x0300)
case SQL_INTERVAL:
return (char *) "SQL_INTERVAL";
break;
#else
case SQL_TIME:
return (char *) "SQL_TIME";
break;
#endif
case SQL_TIMESTAMP:
return (char *) "SQL_TIMESTAMP";
break;
case SQL_LONGVARCHAR:
return (char *) "SQL_LONGVARCHAR";
break;
case SQL_BINARY:
return (char *) "SQL_BINARY";
break;
case SQL_VARBINARY:
return (char *) "SQL_VARBINARY";
break;
case SQL_LONGVARBINARY:
return (char *) "SQL_LONGVARBINARY";
break;
case SQL_BIGINT:
return (char *) "SQL_BIGINT";
break;
case SQL_TINYINT:
return (char *) "SQL_TINYINT";
break;
case SQL_BIT:
return (char *) "SQL_BIT";
break;
#if (ODBCVER >= 0x0350)
case SQL_GUID:
return (char *) "SQL_GUID";
break;
#endif
case SQL_WCHAR:
return (char *) "SQL_WCHAR";
case SQL_WVARCHAR:
return (char *) "SQL_WVARCHAR";
case SQL_WLONGVARCHAR:
return (char *) "SQL_WLONGVARCHAR";
default:
return (char *) "Unknown type";
}
}
static char *
cgw_utype_to_string (int type)
{
switch (type)
{
case CCI_U_TYPE_CHAR:
return (char *) "char";
case CCI_U_TYPE_STRING:
return (char *) "char";
case CCI_U_TYPE_NUMERIC:
return (char *) "numeric";
case CCI_U_TYPE_BIGINT:
return (char *) "bigint";
case CCI_U_TYPE_INT:
return (char *) "integer";
case CCI_U_TYPE_SHORT:
return (char *) "smallint";
case CCI_U_TYPE_FLOAT:
return (char *) "float";
case CCI_U_TYPE_DOUBLE:
return (char *) "double";
case CCI_U_TYPE_DATE:
return (char *) "date";
case CCI_U_TYPE_TIME:
return (char *) "time";
case CCI_U_TYPE_TIMESTAMP:
return (char *) "timestamp";
case CCI_U_TYPE_DATETIME:
return (char *) "datetime";
case CCI_U_TYPE_NULL:
return (char *) "null";
case CCI_U_TYPE_BIT:
return (char *) "bit";
case CCI_U_TYPE_VARBIT:
return (char *) "bit varying";
case CCI_U_TYPE_MONETARY:
return (char *) "monetary";
case CCI_U_TYPE_SET:
return (char *) "set";
case CCI_U_TYPE_MULTISET:
return (char *) "multiset";
case CCI_U_TYPE_SEQUENCE:
return (char *) "sequence";
case CCI_U_TYPE_OBJECT:
return (char *) "object";
case CCI_U_TYPE_BLOB:
return (char *) "blob";
case CCI_U_TYPE_CLOB:
return (char *) "clob";
case CCI_U_TYPE_JSON:
return (char *) "json";
case CCI_U_TYPE_ENUM:
return (char *) "enum";
case CCI_U_TYPE_DATETIMELTZ:
return (char *) "datetimeltz";
case CCI_U_TYPE_DATETIMETZ:
return (char *) "datetimetz";
case CCI_U_TYPE_TIMESTAMPTZ:
return (char *) "timestamptz";
case CCI_U_TYPE_TIMESTAMPLTZ:
return (char *) "timestampltz";
default:
return (char *) "";
}
}
static int
cgw_unicode_to_utf8 (wchar_t * in_src, int in_size, char **out_target, int *out_length)
{
#if defined(WINDOWS)
int length;
unsigned char *in_string = (unsigned char *) in_src;
if (in_string == NULL || out_length == NULL || out_length == NULL)
{
return (-1);
}
if (in_size < 0)
{
return (-1);
}
length = WideCharToMultiByte (CP_UTF8, 0, in_src, -1, conv_str_buff, CONV_STRING_BUF_SIZE, NULL, NULL);
if (length <= 0)
{
return -1;
}
if (out_target)
{
*out_target = conv_str_buff;
}
if (out_length)
{
*out_length = length;
}
#else /* WINDOWS */
iconv_t cd;
size_t ret = 0;
uint16_t *iconv_in = (uint16_t *) in_src;
char *iconv_out = conv_str_buff;
size_t inlen = in_size;
size_t outlen_org = CONV_STRING_BUF_SIZE;
size_t outlen = CONV_STRING_BUF_SIZE;
if (iconv_in == NULL || out_length == NULL || out_length == NULL)
{
return (-1);
}
cd = iconv_open (UTF8_CODE_PAGE, UNICODE_CODE_PAGE);
if (cd == (iconv_t) (-1))
{
return -1;
}
ret = iconv (cd, (char **) &iconv_in, &inlen, &iconv_out, &outlen);
if (ret == (size_t) (-1))
{
iconv_close (cd);
return (-1);
}
iconv_close (cd);
if (out_target)
{
conv_str_buff[outlen_org - outlen] = '\0';
*out_target = conv_str_buff;
}
if (out_length)
{
*out_length = (outlen_org - outlen) + 1;
}
#endif
return 0;
}
static int
cgw_utf8_to_unicode (const char *in_utf8_str, wchar_t * out_unicode_str, size_t out_unicode_strLen)
{
#if defined(WINDOWS)
int result = MultiByteToWideChar (CP_UTF8, 0, in_utf8_str, -1, out_unicode_str, out_unicode_strLen);
if (result == 0)
{
return -1;
}
#else
char *in_buf = (char *) in_utf8_str;
char *out_buf = (char *) out_unicode_str;
size_t in_strlen = strlen (in_utf8_str);
size_t out_strlen = out_unicode_strLen;
iconv_t conv = iconv_open (UNICODE_CODE_PAGE, UTF8_CODE_PAGE);
if (conv == (iconv_t) - 1)
{
return -1;
}
if (iconv (conv, &in_buf, &in_strlen, &out_buf, &out_strlen) == (size_t) (-1))
{
iconv_close (conv);
return -1;
}
*((wchar_t *) out_buf) = L'\0';
iconv_close (conv);
#endif
return 0;
}
static int
cgw_conv_mtow (wchar_t * dest_wc, char *src_mbc)
{
size_t length;
if (src_mbc == NULL || dest_wc == NULL)
{
return -1;
}
length = strlen (src_mbc);
if (length == 0)
{
return -1;
}
CONV_M_TO_W (src_mbc, dest_wc, length);
dest_wc[length] = L'\0';
return 0;
}
static int
cgw_uint32_to_uni16 (uint32_t i, uint16_t * u)
{
if (i < 0xffff)
{
*u = (uint16_t) (i & 0xffff);
return 1;
}
return 0;
}
static SQLWCHAR *
cgw_wchar_to_sqlwchar (wchar_t * src, size_t len)
{
SQLWCHAR *dest;
SQLWCHAR *sqlwchar_string;
size_t i;
if (sizeof (wchar_t) == sizeof (SQLWCHAR))
{
dest = (SQLWCHAR *) malloc (len * sizeof (SQLWCHAR));
memcpy (dest, src, len * sizeof (wchar_t));
return dest;
}
else
{
dest = (SQLWCHAR *) malloc (2 * len * sizeof (SQLWCHAR));
sqlwchar_string = dest;
for (i = 0; i < len; i++)
{
dest += cgw_uint32_to_uni16 ((uint32_t) src[i], (uint16_t *) dest);
}
*dest = 0;
return sqlwchar_string;
}
return NULL;
}
static const char *
cgw_get_dbms_name (T_DBMS_TYPE db_type)
{
for (int i = 0; i < supported_dbms_max_num; i++)
{
if (db_type == supported_dbms_list[i].dbms_type)
{
return supported_dbms_list[i].dbms_name;
}
}
return "";
}