* This file is part of the oGRAC project.
* Copyright (c) 2026 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* convert.c
*
*
* IDENTIFICATION
* src/driver/ogodbc/convert.c
*/
#include "convert.h"
static SQLRETURN handle_fetch_param(og_generate_result *generate_result, bind_input_param *input_param)
{
generate_result->is_recieved = OG_TRUE;
if (input_param->size != NULL) {
*input_param->size = (SQLLEN)generate_result->result_size;
}
return SQL_SUCCESS;
}
static SQLRETURN handle_fetch_err(statement *stmt)
{
stmt->conn->err_sign = 1;
stmt->conn->error_msg = "Invalid string or buffer length";
return SQL_ERROR;
}
static SQLRETURN handle_convert_err(statement *stmt)
{
stmt->conn->err_sign = 1;
stmt->conn->error_msg = "Failed to convert datatype";
return SQL_ERROR;
}
static SQLRETURN get_c_char_type_param(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param)
{
status_t status;
if (input_param->param_len <= 0) {
return handle_fetch_err(stmt);
}
generate_result->is_str = OG_TRUE;
if (generate_result->is_col) {
status = ogconn_column_as_string(stmt->ctconn_stmt,
generate_result->ptr,
(char *)input_param->param_value,
input_param->param_len);
} else {
status = ogconn_outparam_as_string_by_id(stmt->ctconn_stmt,
generate_result->ptr,
(char *)input_param->param_value,
input_param->param_len);
}
if (status == OG_SUCCESS) {
generate_result->result_size = (uint32)strlen((char *)input_param->param_value);
handle_fetch_param(generate_result, input_param);
}
if (status != OG_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
return SQL_SUCCESS;
}
static SQLRETURN get_db_lob_param(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
unsigned int param_buf = 0;
unsigned int nchars = 0;
unsigned int nbytes = 0;
status_t status;
unsigned int flag = 0;
unsigned int data_size = 0;
if (input_param->param_len <= 0) {
return handle_fetch_err(stmt);
}
data_size = input_param->param_len;
if (generate_result->is_str) {
data_size = data_size - 1;
}
switch (data_result->og_type) {
case OGCONN_TYPE_BLOB:
case OGCONN_TYPE_IMAGE:
status = ogconn_read_blob_by_id(stmt->ctconn_stmt, generate_result->ptr,
generate_result->result_size,
input_param->param_value, data_size,
&nbytes, &flag);
param_buf = nbytes;
break;
case OGCONN_TYPE_CLOB:
status = ogconn_read_clob_by_id(stmt->ctconn_stmt, generate_result->ptr,
generate_result->result_size,
input_param->param_value, data_size,
&nchars, &nbytes, &flag);
param_buf = nchars;
break;
default:
stmt->conn->err_sign = 1;
stmt->conn->error_msg = "db data type decoding failed";
return SQL_ERROR;
}
generate_result->result_size += nbytes;
if (status != OGCONN_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
if (param_buf < input_param->param_len && generate_result->is_str) {
((char *)input_param->param_value)[param_buf] = '\0';
}
if (input_param->size != NULL) {
*input_param->size = (SQLLEN)param_buf;
}
if (flag) {
generate_result->is_recieved = OG_TRUE;
return SQL_SUCCESS;
}
if (input_param->size != NULL) {
*input_param->size = (SQLLEN)SQL_NO_TOTAL;
}
return SQL_SUCCESS_WITH_INFO;
}
static SQLRETURN get_str_param(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
unsigned int remaining_len = 0;
unsigned int actual_len = 0;
if (input_param->param_len <= 0) {
return handle_fetch_err(stmt);
}
generate_result->is_str = OG_TRUE;
remaining_len = data_result->len - generate_result->result_size;
if (remaining_len >= input_param->param_len && generate_result->is_str) {
actual_len = input_param->param_len - 1;
} else if (remaining_len > input_param->param_len && !generate_result->is_str) {
actual_len = input_param->param_len;
} else {
actual_len = remaining_len;
generate_result->is_recieved = OG_TRUE;
}
if (actual_len > 0) {
if (memcpy_s(input_param->param_value, input_param->param_len,
data_result->value + generate_result->result_size, actual_len) != 0) {
stmt->conn->err_sign = 1;
stmt->conn->error_msg = "secure C lib has throw an error.";
return SQL_ERROR;
}
}
if (input_param->size != NULL) {
if (generate_result->is_recieved) {
*input_param->size = (SQLLEN)actual_len;
} else {
*input_param->size = remaining_len;
}
}
if (generate_result->is_str && input_param->param_len > actual_len) {
((char *)input_param->param_value)[actual_len] = 0;
}
generate_result->result_size = generate_result->result_size + actual_len;
return SQL_SUCCESS;
}
static SQLRETURN get_c_wchar_type_param(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
char value[DECIMAL_MOD];
unsigned int end = OG_FALSE;
status_t status;
int value_len = 0;
char *data = (char *)input_param->param_value;
unsigned int input_size = (unsigned int)strlen((const char *)input_param->param_value);
int param_size = 0;
generate_result->is_str = OG_TRUE;
if (input_param->param_len <= sizeof(WCHAR)) {
return handle_fetch_err(stmt);
}
if (generate_result->is_col) {
status = ogconn_column_as_string(stmt->ctconn_stmt, generate_result->ptr, data,
input_param->param_len);
} else {
status = ogconn_outparam_as_string_by_id(stmt->ctconn_stmt, generate_result->ptr,
data, input_param->param_len);
}
if (status != OG_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
param_size = ogconn_transcode_ucs2(stmt->ctconn_stmt, (void *)input_param->param_value,
&input_size, (void *)value, DECIMAL_MOD, &end);
if (param_size < 0) {
get_err(stmt->conn);
return SQL_ERROR;
}
value_len = input_param->param_len - sizeof(SQLWCHAR);
if (value_len < param_size) {
param_size = value_len;
}
generate_result->result_size = param_size;
if (memcpy_s(input_param->param_value, value_len, value, param_size) != 0) {
stmt->conn->err_sign = 1;
stmt->conn->error_msg = "secure C lib has throw an error.";
return SQL_ERROR;
}
data[param_size] = '\0';
data[param_size + 1] = '\0';
handle_fetch_param(generate_result, input_param);
return SQL_SUCCESS;
}
static SQLRETURN get_c_date_param(og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
TIME_STRUCT *time_param = NULL;
DATE_STRUCT *date_param = NULL;
TIMESTAMP_STRUCT *timestamp_param = NULL;
date_detail_t detail;
date_t date_input = *(date_t *)data_result->value;
uint32 mill = 0;
uint32 micro = 0;
cm_decode_date(date_input, &detail);
if (input_param->sql_type == SQL_C_TIME || input_param->sql_type == SQL_C_TYPE_TIME) {
time_param = (TIME_STRUCT *)input_param->param_value;
generate_result->result_size = (uint32)sizeof(TIME_STRUCT);
time_param->hour = detail.hour;
time_param->minute = detail.min;
time_param->second = detail.sec;
} else if (input_param->sql_type == SQL_C_DATE || input_param->sql_type == SQL_C_TYPE_DATE) {
date_param = (DATE_STRUCT *)input_param->param_value;
generate_result->result_size = (uint32)sizeof(DATE_STRUCT);
date_param->year = detail.year;
date_param->month = detail.mon;
date_param->day = detail.day;
} else {
timestamp_param = (TIMESTAMP_STRUCT *)input_param->param_value;
micro = ((uint32)detail.microsec) * NANOSECS_PER_MICROSEC;
mill = ((uint32)detail.millisec) * NANOSECS_PER_MILLISEC;
generate_result->result_size = (uint32)sizeof(TIMESTAMP_STRUCT);
timestamp_param->year = detail.year;
timestamp_param->month = detail.mon;
timestamp_param->day = detail.day;
timestamp_param->hour = detail.hour;
timestamp_param->minute = detail.min;
timestamp_param->second = detail.sec;
timestamp_param->fraction = mill + micro;
}
return handle_fetch_param(generate_result, input_param);
}
static SQLRETURN handle_decimal_param_scale(dec8_t *param_t, SQL_NUMERIC_STRUCT *param_value)
{
errno_t errcode;
status_t power_status;
status_t mul_status;
status_t mod_status;
status_t divide_status;
status_t floor_status;
dec8_t dec;
dec8_t precision;
dec8_t dec_fac;
dec8_t mul_result;
dec8_t dec_mod;
dec8_t left_v;
dec8_t ratio;
size_t param_size = sizeof(param_value->val);
uint32 radix = 10;
uint32 max_zero_num = 16;
uint32 p = 0;
errcode = memset_s(param_value->val, param_size, 0, param_size);
if (errcode != 0) {
return SQL_ERROR;
}
cm_uint32_to_dec8(param_value->scale, &precision);
cm_uint32_to_dec8(radix, &dec);
power_status = cm_dec8_power(&dec, &precision, &dec_fac);
cm_dec8_abs(param_t);
cm_uint32_to_dec8(DECIMAL_MOD, &dec_mod);
mul_status = cm_dec8_multiply(param_t, &dec_fac, &mul_result);
if (power_status != OG_SUCCESS || mul_status != OG_SUCCESS) {
return SQL_ERROR;
}
while (mul_result.len != 1) {
if (mul_result.head == ZERO_D8EXPN ||
mul_result.head == NON_NEG_ZERO_D8EXPN ||
mul_result.head == NEG_ZERO_D8EXPN) {
break;
}
if (p >= max_zero_num) {
break;
}
mod_status = cm_dec8_mod(&mul_result, &dec_mod, &left_v);
divide_status = cm_dec8_divide(&mul_result, &dec_mod, &ratio);
floor_status = cm_dec8_floor(&ratio);
if (mod_status != OG_SUCCESS || divide_status != OG_SUCCESS || floor_status != OG_SUCCESS) {
return SQL_ERROR;
}
mul_result = ratio;
param_value->val[p] = (left_v.len == 1) ? (SQLCHAR)0 : (SQLCHAR)left_v.cells[0];
p++;
}
if (mul_result.len == 1 && (mul_result.head == ZERO_D8EXPN
|| mul_result.head == NON_NEG_ZERO_D8EXPN
|| mul_result.head == NEG_ZERO_D8EXPN)) {
return SQL_SUCCESS;
}
return SQL_SUCCESS_WITH_INFO;
}
static SQLRETURN get_c_numeric_value(statement *stmt,
og_generate_result *generate_result,
dec8_t *numeric_value,
bind_input_param *input_param)
{
SQLRETURN ret;
int32 num_count = 0;
int8 dec_exp = 0;
int8 sign = 0;
int32 prec_count = 0;
SQL_NUMERIC_STRUCT *param_value = input_param->param_value;
int32 prec_num = 10;
int32 prec_val = CALC_PREC_SINGAL;
uint8 dec_mod = numeric_value->len - 1;
dec8_t param_t;
cm_dec8_copy(¶m_t, numeric_value);
uint8 max_check = 10;
uint8 expn_num = 8;
uint8 len_offset = 2;
param_value->scale = 0;
param_value->sign = numeric_value->sign;
param_value->precision = 0;
if (dec_mod > 0) {
while (prec_val >= max_check) {
if (numeric_value->cells[0] / prec_val > 0) {
break;
}
prec_val = prec_val / max_check;
num_count++;
}
dec_exp = (!numeric_value->sign ? (NEG_ZERO_D8EXPN - numeric_value->head)
: (numeric_value->head - NON_NEG_ZERO_D8EXPN));
sign = dec_exp + 1;
if (sign <= 0) {
param_value->scale = param_value->precision;
}
while (prec_num <= CALC_PREC_SINGAL) {
if (numeric_value->cells[numeric_value->len - len_offset] % prec_num > 0) {
break;
}
prec_num = prec_num * max_check;
prec_count++;
}
if (sign > 0 && sign < dec_mod) {
param_value->scale = dec_mod * expn_num - prec_count - sign * expn_num;
}
if (sign > 0 && sign < dec_mod) {
param_value->precision = dec_mod * expn_num - num_count - prec_count;
} else if (sign <= 0) {
param_value->precision = dec_mod * expn_num - prec_count + sign * (-1) * expn_num;
} else {
param_value->precision = sign * expn_num - num_count;
}
}
ret = handle_decimal_param_scale(¶m_t, param_value);
if (ret != SQL_SUCCESS) {
return handle_convert_err(stmt);
}
generate_result->result_size = (unsigned int)sizeof(SQL_NUMERIC_STRUCT);
return handle_fetch_param(generate_result, input_param);
}
static SQLRETURN get_c_float_by_db_str(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
text_t src_data;
src_data.str = data_result->value;
src_data.len = data_result->len;
double ex_data = 0.0;
double round_data = 0.0;
if (cm_text2real_ex(&src_data, &ex_data) != NERR_SUCCESS) {
return handle_convert_err(stmt);
}
if (input_param->sql_type == SQL_C_FLOAT) {
*(float *)input_param->param_value = (float)ex_data;
generate_result->result_size = (uint32)sizeof(float);
} else if (input_param->sql_type == SQL_C_LONG || input_param->sql_type == SQL_C_SLONG) {
round_data = cm_round_real(ex_data, ROUND_HALF_UP);
if (round_data > OG_MAX_INT32 || round_data < OG_MIN_INT32) {
return handle_convert_err(stmt);
}
*(int *)input_param->param_value = (int)round_data;
generate_result->result_size = (uint32)sizeof(int);
} else {
round_data = cm_round_real(ex_data, ROUND_HALF_UP);
if (round_data > OG_MAX_INT16 || round_data < OG_MIN_INT16) {
return handle_convert_err(stmt);
}
*(short *)input_param->param_value = (short)round_data;
generate_result->result_size = (uint32)sizeof(short);
}
return handle_fetch_param(generate_result, input_param);
}
static SQLRETURN get_db_int_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
int32 value = 0;
switch (input_param->sql_type) {
case SQL_C_LONG:
case SQL_C_SBIGINT:
case SQL_C_SLONG:
*(int *)input_param->param_value = *(int *)data_result->value;
generate_result->result_size = (uint32)sizeof(int);
return handle_fetch_param(generate_result, input_param);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_TINYINT:
case SQL_C_STINYINT:
value = *(int *)data_result->value;
if (value > OG_MAX_INT16 || value < OG_MIN_INT16) {
return handle_convert_err(stmt);
}
*(short *)input_param->param_value = (short)value;
generate_result->result_size = (uint32)sizeof(short);
return handle_fetch_param(generate_result, input_param);
case SQL_C_NUMERIC:
case SQL_C_DOUBLE:
*(double *)input_param->param_value = (double)(*(int *)data_result->value);
generate_result->result_size = (uint32)sizeof(double);
return handle_fetch_param(generate_result, input_param);
case SQL_C_FLOAT:
*(float *)input_param->param_value = (float)(*(int *)data_result->value);
generate_result->result_size = (uint32)sizeof(float);
return handle_fetch_param(generate_result, input_param);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from int is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_uint_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
uint32 value = 0;
switch (input_param->sql_type) {
case SQL_C_LONG:
case SQL_C_SBIGINT:
case SQL_C_SLONG:
value = *(uint32 *)data_result->value;
if (value > OG_MAX_INT32) {
return handle_convert_err(stmt);
}
*(int *)input_param->param_value = (int)value;
generate_result->result_size = (uint32)sizeof(int);
return handle_fetch_param(generate_result, input_param);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_TINYINT:
case SQL_C_STINYINT:
value = *(uint32 *)data_result->value;
if (value > OG_MAX_INT16) {
return handle_convert_err(stmt);
}
*(short *)input_param->param_value = (short)value;
generate_result->result_size = (uint32)sizeof(short);
return handle_fetch_param(generate_result, input_param);
case SQL_C_NUMERIC:
case SQL_C_DOUBLE:
*(double *)input_param->param_value = (double)(*(uint32 *)data_result->value);
generate_result->result_size = (uint32)sizeof(double);
return handle_fetch_param(generate_result, input_param);
case SQL_C_FLOAT:
*(float *)input_param->param_value = (float)(*(uint32 *)data_result->value);
generate_result->result_size = (uint32)sizeof(float);
return handle_fetch_param(generate_result, input_param);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from uint is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_bool_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
uint32 value = 0;
switch (input_param->sql_type) {
case SQL_C_LONG:
case SQL_C_SBIGINT:
case SQL_C_SLONG:
*(int *)input_param->param_value = (int)*(uint32 *)data_result->value;
generate_result->result_size = (uint32)sizeof(int);
return handle_fetch_param(generate_result, input_param);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_TINYINT:
case SQL_C_STINYINT:
value = *(uint32 *)data_result->value;
if (value > OG_MAX_INT16) {
return handle_convert_err(stmt);
}
*(short *)input_param->param_value = (short)value;
generate_result->result_size = (uint32)sizeof(short);
return handle_fetch_param(generate_result, input_param);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from bool is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_bigint_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
int64 value = *(int64 *)data_result->value;
switch (input_param->sql_type) {
case SQL_C_LONG:
case SQL_C_SBIGINT:
case SQL_C_SLONG:
if (value > OG_MAX_INT32 || value < OG_MIN_INT32) {
return handle_convert_err(stmt);
}
*(int *)(input_param->param_value) = (int)value;
generate_result->result_size = (uint32)sizeof(int);
return handle_fetch_param(generate_result, input_param);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_TINYINT:
case SQL_C_STINYINT:
if (value > OG_MAX_INT16 || value < OG_MIN_INT16) {
return handle_convert_err(stmt);
}
*(short *)(input_param->param_value) = (short)value;
generate_result->result_size = (uint32)sizeof(short);
return handle_fetch_param(generate_result, input_param);
case SQL_C_NUMERIC:
case SQL_C_DOUBLE:
*(double *)input_param->param_value = (double)(*(int64 *)data_result->value);
generate_result->result_size = (uint32)sizeof(double);
return handle_fetch_param(generate_result, input_param);
case SQL_C_FLOAT:
*(float *)input_param->param_value = (float)(*(int64 *)data_result->value);
generate_result->result_size = (uint32)sizeof(float);
return handle_fetch_param(generate_result, input_param);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from bigint is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_real_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
switch (input_param->sql_type) {
case SQL_C_NUMERIC:
case SQL_C_DOUBLE:
*(double *)input_param->param_value = *(double *)data_result->value;
generate_result->result_size = (uint32)sizeof(double);
return handle_fetch_param(generate_result, input_param);
case SQL_C_FLOAT:
*(float *)input_param->param_value = (float)*(double *)data_result->value;
generate_result->result_size = (uint32)sizeof(float);
return handle_fetch_param(generate_result, input_param);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from real is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_number2_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
dec2_t double_value;
const payload_t *dv = (const payload_t *)data_result->value;
uint8 len = (uint8)data_result->len;
status_t status;
dec8_t numeric_value;
switch (input_param->sql_type) {
case SQL_C_NUMERIC:
status = cm_dec_2_to_8(&numeric_value, dv, len);
if (status != OG_SUCCESS) {
return SQL_ERROR;
}
return get_c_numeric_value(stmt, generate_result, &numeric_value, input_param);
case SQL_C_FLOAT:
cm_dec2_copy_ex(&double_value, dv, len);
generate_result->result_size = (uint32)sizeof(float);
*(float *)input_param->param_value = (float)cm_dec2_to_real(&double_value);
return handle_fetch_param(generate_result, input_param);
case SQL_C_DOUBLE:
cm_dec2_copy_ex(&double_value, dv, len);
generate_result->result_size = (uint32)sizeof(double);
*(double *)input_param->param_value = cm_dec2_to_real(&double_value);
return handle_fetch_param(generate_result, input_param);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from number2 is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_number_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
dec4_t *number_value = (dec4_t *)data_result->value;
status_t status;
dec8_t number_value8;
uint32 byte = 0;
switch (input_param->sql_type) {
case SQL_C_NUMERIC:
byte = ((uint32)(1 + number_value->ncells)) * sizeof(c4typ_t);
status = cm_dec_4_to_8(&number_value8, number_value, byte);
if (status != OG_SUCCESS) {
return SQL_ERROR;
}
return get_c_numeric_value(stmt, generate_result, &number_value8, input_param);
case SQL_C_FLOAT:
generate_result->result_size = (uint32)sizeof(float);
*(float *)input_param->param_value = (float)cm_dec4_to_real((dec4_t *)data_result->value);
return handle_fetch_param(generate_result, input_param);
case SQL_C_DOUBLE:
generate_result->result_size = (uint32)sizeof(double);
*(double *)input_param->param_value = cm_dec4_to_real((dec4_t *)data_result->value);
return handle_fetch_param(generate_result, input_param);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from number is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_date_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
switch (input_param->sql_type) {
case SQL_C_DATE:
case SQL_C_TYPE_DATE:
case SQL_C_TIMESTAMP:
case SQL_C_TYPE_TIMESTAMP:
case SQL_C_TIME:
case SQL_C_TYPE_TIME:
return get_c_date_param(generate_result, input_param, data_result);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from date is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_raw_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
switch (input_param->sql_type) {
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from raw is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_timestamp_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
switch (input_param->sql_type) {
case SQL_C_DATE:
case SQL_C_TYPE_DATE:
case SQL_C_TIMESTAMP:
case SQL_C_TYPE_TIMESTAMP:
case SQL_C_TIME:
case SQL_C_TYPE_TIME:
return get_c_date_param(generate_result, input_param, data_result);
case SQL_C_CHAR:
return get_c_char_type_param(stmt, generate_result, input_param);
case SQL_C_WCHAR:
return get_c_wchar_type_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from timestamp is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_clob_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
switch (input_param->sql_type) {
case SQL_C_CHAR:
case SQL_C_WCHAR:
generate_result->is_str = OG_TRUE;
return get_db_lob_param(stmt, generate_result, input_param, data_result);
case SQL_C_BINARY:
return get_db_lob_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from clob is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_default_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
switch (input_param->sql_type) {
case SQL_C_CHAR:
case SQL_C_WCHAR:
return get_str_param(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_db_string_value(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
connection_class *conn = stmt->conn;
text_t result_data;
result_data.str = data_result->value;
result_data.len = data_result->len;
switch (input_param->sql_type) {
case SQL_C_CHAR:
case SQL_C_WCHAR:
return get_str_param(stmt, generate_result, input_param, data_result);
case SQL_C_DOUBLE:
if (cm_text2real_ex(&result_data, (double *)input_param->param_value) != NERR_SUCCESS) {
return handle_convert_err(stmt);
}
generate_result->result_size = (uint32)sizeof(double);
return handle_fetch_param(generate_result, input_param);
case SQL_C_LONG:
case SQL_C_SLONG:
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_FLOAT:
return get_c_float_by_db_str(stmt, generate_result, input_param, data_result);
default:
conn->err_sign = 1;
conn->error_msg = "conversion type from char is not supported.";
return SQL_ERROR;
}
}
static SQLRETURN get_fetch_param(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param,
og_fetch_data_result *data_result)
{
generate_result->sql_type = input_param->sql_type;
data_result->og_type = generate_result->og_type;
switch (generate_result->og_type) {
case OGCONN_TYPE_INTEGER:
return get_db_int_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_UINT32:
return get_db_uint_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_BOOLEAN:
return get_db_bool_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_BIGINT:
return get_db_bigint_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_REAL:
return get_db_real_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_NUMBER2:
return get_db_number2_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_DECIMAL:
case OGCONN_TYPE_NUMBER:
return get_db_number_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_RAW:
return get_db_raw_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_DATE:
return get_db_date_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_TIMESTAMP:
case OGCONN_TYPE_TIMESTAMP_TZ_FAKE:
case OGCONN_TYPE_TIMESTAMP_TZ:
case OGCONN_TYPE_TIMESTAMP_LTZ:
return get_db_timestamp_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_CLOB:
case OGCONN_TYPE_BLOB:
return get_db_clob_value(stmt, generate_result, input_param, data_result);
case OGCONN_TYPE_CHAR:
case OGCONN_TYPE_VARCHAR:
case OGCONN_TYPE_STRING:
return get_db_string_value(stmt, generate_result, input_param, data_result);
default:
return get_db_default_value(stmt, generate_result, input_param, data_result);
}
return SQL_SUCCESS;
}
SQLRETURN build_fetch_param(statement *stmt, uint32 total_param)
{
uint32 param_len = 0;
char *fetch_value = NULL;
sql_input_data *input_data = NULL;
int32 index = 0;
og_generate_result generate_result;
bind_input_param input_param;
og_fetch_data_result fetch_result;
ogconn_outparam_desc_t outparam_info;
bilist_t *params = &stmt->params;
SQLRETURN ret;
uint32 has_param = 0;
uint32 p = 0;
status_t status;
while (p < stmt->params.count) {
input_data = generate_bind_param_instance(params->head, p);
if (input_data == NULL || input_data->param_type == OGCONN_INPUT) {
continue;
}
if (total_param <= index) {
break;
}
input_param.sql_type = input_data->sql_type;
input_param.param_value = input_data->param_value;
input_param.param_len = input_data->param_len;
input_param.size = input_data->size;
status = ogconn_desc_outparam_by_id(stmt->ctconn_stmt, index, &outparam_info);
if (status != OGCONN_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
status = ogconn_get_outparam_by_id(stmt->ctconn_stmt, index, (void **)&fetch_value, ¶m_len, &has_param);
if (status != OGCONN_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
index = index + 1;
if (has_param || param_len == 0) {
continue;
}
fetch_result.value = fetch_value;
fetch_result.len = param_len;
generate_result.ptr = input_data->index;
generate_result.result_size = 0;
generate_result.sql_type = SQL_C_CHAR;
generate_result.is_recieved = OG_FALSE;
generate_result.is_str = OG_FALSE;
generate_result.field_name = outparam_info.name;
generate_result.og_type = outparam_info.type;
generate_result.is_col = OG_FALSE;
ret = get_fetch_param(stmt, &generate_result, &input_param, &fetch_result);
if (ret != SQL_SUCCESS) {
return ret;
}
p++;
}
return SQL_SUCCESS;
}
SQLRETURN ograc_sql_bind_param(statement *stmt,
SQLUSMALLINT param_num,
SQLSMALLINT input_type,
SQLSMALLINT value_type,
SQLSMALLINT param_type,
SQLULEN column_len,
SQLSMALLINT dec_number,
SQLPOINTER value_ptr,
SQLLEN buf_size,
SQLLEN *str_size)
{
sql_input_data *input_data = NULL;
uint32 data_len = 0;
uint32 data_total = 0;
SQLULEN param_len = 0;
status_t status;
ogconn_type_t og_type;
uint32 size = 0;
if (param_num <= 0 || (value_ptr == NULL && str_size == NULL)) {
return SQL_ERROR;
}
input_data = build_bind_param(&(stmt->params), (param_num - 1));
if (input_data == NULL) {
return SQL_INVALID_HANDLE;
}
input_data->param_value = value_ptr;
input_data->size = str_size;
input_data->number = dec_number;
og_type = sql_type_map_to_db_type(param_type);
if (og_type == OGCONN_TYPE_UNKNOWN) {
return SQL_ERROR;
}
input_data->og_type = og_type;
if (value_type == SQL_C_DEFAULT) {
value_type = db_type_map_to_c_type(og_type);
}
input_data->sql_type = value_type;
switch (input_type) {
case SQL_PARAM_INPUT:
input_data->param_type = OGCONN_INPUT;
break;
case SQL_PARAM_OUTPUT:
input_data->param_type = OGCONN_OUTPUT;
break;
case SQL_PARAM_INPUT_OUTPUT:
input_data->param_type = OGCONN_INOUT;
break;
default:
return SQL_ERROR;
}
if (stmt->stmt_flag == INIT_STMT) {
input_data->param_flag = INIT_PARAM;
} else if (stmt->stmt_flag == NOT_EXEC_STMT) {
input_data->param_flag = NOT_EXEC_PARAM;
} else {
input_data->param_flag = FREE_PARAM;
}
size = (uint32)sizeof(int);
status = ogconn_get_stmt_attr(stmt->ctconn_stmt, OGCONN_ATTR_PARAMSET_SIZE, &data_len, size, &size);
if (status != OGCONN_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
if (data_len == 0) {
return SQL_ERROR;
}
input_data->param_count = data_len;
param_len = cal_column_len(value_type, column_len, buf_size, value_ptr, str_size);
input_data->param_len = param_len;
input_data->is_convert = OG_FALSE;
input_data->is_process = OG_FALSE;
input_data->is_binded = OG_FALSE;
if (value_ptr == NULL) {
for (uint32 i = 0; i < data_len; i++) {
if (str_size[i] != SQL_DEFAULT_PARAM && str_size[i] != SQL_NULL_DATA
&& str_size[i] != SQL_DATA_AT_EXEC) {
return SQL_ERROR;
}
}
}
input_data->param_stream = NULL;
input_data->param_offset = 0;
status = ogconn_get_stmt_attr(stmt->ctconn_stmt, OGCONN_ATTR_PARAM_COUNT, &data_total, sizeof(data_total), NULL);
if (status != OGCONN_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
if (input_data->index >= data_total) {
return SQL_SUCCESS;
}
if (bind_param_by_c_type(stmt, input_data) != OGCONN_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
return SQL_SUCCESS;
}
static SQLRETURN get_fetch_data(statement *stmt,
og_generate_result *generate_result,
bind_input_param *input_param)
{
uint32 data_len = 0;
uint32 has_data = 0;
og_fetch_data_result data_result;
void *value = NULL;
ogconn_inner_column_desc_t column_info;
status_t status;
if (ogconn_get_column_by_id(stmt->ctconn_stmt, generate_result->ptr,
&value, &data_len, &has_data) != OGCONN_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
if (has_data || data_len <= 0) {
if (input_param->size != NULL) {
*(input_param->size) = has_data ? SQL_NULL_DATA : 0;
}
if (input_param->param_value != NULL) {
*(char*)input_param->param_value = 0;
}
generate_result->is_recieved = OG_TRUE;
return SQL_SUCCESS;
}
if (generate_result->og_type == OGCONN_TYPE_UNKNOWN) {
status = ogconn_desc_inner_column_by_id(stmt->ctconn_stmt, generate_result->ptr, &column_info);
if (status != OG_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
generate_result->col_label = column_info.name;
generate_result->og_type = column_info.type;
}
data_result.value = value;
data_result.len = data_len;
return get_fetch_param(stmt, generate_result, input_param, &data_result);
}
static SQLRETURN fetch_data_and_bind_col(statement *stmt, SQLULEN fetch_pos)
{
column_param *col_param = NULL;
char *item_buf = NULL;
pointer_t ptr;
bind_input_param input_param;
uint32 p = 0;
SQLRETURN ret;
list_t *param_list = &(stmt->param);
while (p < param_list->count) {
item_buf = (char *)param_list->extents[p / param_list->extent_step];
ptr = item_buf + (p % param_list->extent_step) * param_list->item_size;
col_param = (column_param *)ptr;
if (col_param->value != NULL) {
input_param.sql_type = col_param->sql_type;
input_param.param_value = col_param->value + col_param->col_len * fetch_pos;
input_param.param_len = col_param->col_len;
input_param.size = col_param->size + fetch_pos;
col_param->generate_result.is_recieved = OG_FALSE;
col_param->generate_result.result_size = 0;
ret = get_fetch_data(stmt, &col_param->generate_result, &input_param);
if (ret != SQL_SUCCESS) {
return ret;
}
}
p++;
}
return SQL_SUCCESS;
}
SQLRETURN ograc_fetch_data(statement *stmt)
{
uint32 num = 0;
uint32 param_count = 0;
int32 status = 0;
SQLRETURN ret;
uint32 total_param = 0;
uint32 p = 0;
uint32 fetch_num = stmt->data_num;
cm_reset_list(&(stmt->data_rows));
stmt->rows = 0;
ogconn_get_stmt_attr(stmt->ctconn_stmt, OGCONN_ATTR_OUTPARAM_COUNT, &total_param, sizeof(uint32), NULL);
if (total_param != 0) {
ogconn_fetch_outparam(stmt->ctconn_stmt, ¶m_count);
ret = build_fetch_param(stmt, total_param);
if (ret != SQL_SUCCESS) {
return ret;
}
}
while (p < fetch_num) {
status = ogconn_fetch(stmt->ctconn_stmt, &num);
stmt->rows += num;
if (status != OG_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
if (num == 0) {
ret = SQL_NO_DATA;
} else {
ret = fetch_data_and_bind_col(stmt, p);
}
if (p != 0 && ret == SQL_NO_DATA) {
break;
}
if (ret != SQL_SUCCESS) {
return ret;
}
p++;
}
return SQL_SUCCESS;
}
SQLRETURN ograc_get_data(statement *stmt,
SQLUSMALLINT col_num,
SQLSMALLINT ctype,
SQLPOINTER data,
SQLLEN buf_size,
SQLLEN *strlen)
{
bind_input_param input_param;
og_generate_result *generate_result = NULL;
og_generate_result *generate_result_temp = NULL;
uint32 p = 0;
uint32 data_num = stmt->data_rows.count;
if (data == NULL || col_num == 0) {
return SQL_ERROR;
}
while (p < data_num) {
generate_result_temp = (og_generate_result *)cm_list_get(&stmt->data_rows, p);
if (generate_result_temp->ptr == (uint32)(col_num - 1)) {
generate_result = generate_result_temp;
break;
}
p++;
}
if (generate_result == NULL) {
if (cm_list_new(&(stmt->data_rows), (void **)&generate_result) != OG_ERROR) {
generate_result->ptr = (uint32)(col_num - 1);
generate_result->sql_type = SQL_C_DEFAULT;
generate_result->result_size = 0;
generate_result->is_recieved = OG_FALSE;
generate_result->is_str = OG_FALSE;
generate_result->is_col = OG_TRUE;
generate_result->og_type = OGCONN_TYPE_UNKNOWN;
}
}
input_param.size = strlen;
input_param.param_value = data;
input_param.sql_type = ctype;
input_param.param_len = buf_size;
if (generate_result == NULL) {
return SQL_INVALID_HANDLE;
}
if (generate_result->is_recieved == OG_TRUE) {
return SQL_NO_DATA;
}
return get_fetch_data(stmt, generate_result, &input_param);
}
static status_t write_data(statement *stmt, sql_input_data *input_data, SQLPOINTER data, SQLLEN size)
{
status_t status;
uint32 remain_len = (unsigned int)size;
uint32 nchars = 0;
uint32 os_len = 0;
switch (input_data->og_type) {
case OGCONN_TYPE_CLOB:
status = ogconn_write_clob(stmt->ctconn_stmt, input_data->index, data, remain_len, &nchars);
if (status != OG_SUCCESS) {
return status;
}
os_len = nchars;
break;
default:
if (size == 0 || input_data->param_stream == NULL) {
return OG_SUCCESS;
}
if (memcpy_s(input_data->param_stream + input_data->param_offset, remain_len, data, remain_len) != 0) {
stmt->conn->err_sign = 1;
stmt->conn->error_msg = "secure C lib has throw an error.";
return SQL_ERROR;
}
os_len = remain_len;
}
input_data->param_offset += os_len;
return OG_SUCCESS;
}
SQLRETURN ograc_put_data(statement *stmt, SQLPOINTER data, SQLLEN size)
{
sql_input_data *input_data = NULL;
bilist_t *datas = &(stmt->params);
uint32 index = 0;
uint32 param_num = datas->count;
status_t status = OG_SUCCESS;
while (index < param_num) {
input_data = generate_bind_param_instance(datas->head, index);
if (input_data == NULL) {
continue;
}
if (input_data->param_value == data || input_data->is_process == SQL_TRUE) {
break;
}
index++;
}
if (input_data == NULL) {
return SQL_ERROR;
}
if (data != NULL && size != 0) {
status = write_data(stmt, input_data, data, size);
}
if (status == OG_SUCCESS) {
input_data->is_binded = SQL_TRUE;
}
if (status != OG_SUCCESS) {
get_err(stmt->conn);
return SQL_ERROR;
}
return SQL_SUCCESS;
}