* This file is part of the oGRAC project.
* Copyright (c) 2024 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.
* -------------------------------------------------------------------------
*
* ogconn_client.c
*
*
* IDENTIFICATION
* src/driver/ogconn/ogconn_client.c
*
* -------------------------------------------------------------------------
*/
#include "ogconn_inner.h"
#include "ogconn_client.h"
#include "ogconn_stmt.h"
#include "ogconn_lob.h"
#include "ogconn_fetch.h"
#ifdef __cplusplus
extern "C" {
#endif
enum en_array_format_type {
ARRAY_USE_BRACE = 0,
ARRAY_USE_SQUARE_BRACKET = 1
};
#define CLT_ARRAY_MORE *(uint32 *)"..."
#define CLT_ARRAY_PRE_FOR_EXP "array["
#define CLT_ARRAY_END_FOR_EXP "]"
#define CLT_ARRAY_PRE_FOR_DISPLAY '{'
#define CLT_ARRAY_END_FOR_DISPLAY "}"
#define CLT_ARRAY_NULL_FOR_EXP "array[]"
#define CLT_ARRAY_NULL_FOR_DISPLAY "{}"
#define CLT_ARRAY_MORE_ELE_FOR_DISPLAY ", ...}"
2) 8K + 2(single quotes)
3) for example: '1234567890abcdefghijklmnopqrstu' */
#define CLT_MAX_LEN_WITH_SINGLE_QUOTE_MARK (OG_MAX_COLUMN_SIZE + 2)
and these single quote should be use another single quote as escape character
2) 2 * 8K + 2(single quotes)
3) for example: '''123''456''7890abcdefghijklmnopqrstu', there are three single quotes in it */
#define CLT_MAX_LEN_WITH_SINGLE_QUOTE_MARK2 (2 * OG_MAX_COLUMN_SIZE + 2)
void ogconn_get_error_position(ogconn_conn_t pconn, uint16 *line, uint16 *column)
{
clt_conn_t *conn = (clt_conn_t *)pconn;
if (SECUREC_UNLIKELY(line == NULL || column == NULL)) {
OG_THROW_ERROR(ERR_CLT_OBJECT_IS_NULL, "line or column");
return;
}
if (SECUREC_UNLIKELY(conn == NULL)) {
*line = 0;
*column = 0;
} else {
*line = conn->loc.line;
*column = conn->loc.column;
}
}
void ogconn_get_error(ogconn_conn_t pconn, int32 *code, const char **message)
{
clt_conn_t *conn = (clt_conn_t *)pconn;
if (SECUREC_UNLIKELY(code == NULL)) {
OG_THROW_ERROR(ERR_CLT_OBJECT_IS_NULL, "error code");
return;
}
if (SECUREC_UNLIKELY(message == NULL)) {
OG_THROW_ERROR(ERR_CLT_OBJECT_IS_NULL, "message");
return;
}
if (SECUREC_UNLIKELY(conn == NULL)) {
cm_get_error(code, message, NULL);
} else {
if (conn->error_code == ERR_ERRNO_BASE) {
clt_copy_local_error(conn);
}
*code = conn->error_code;
*message = conn->message;
}
}
char *ogconn_get_message(ogconn_conn_t pconn)
{
clt_conn_t *conn = (clt_conn_t *)pconn;
if (SECUREC_UNLIKELY(conn == NULL)) {
OG_THROW_ERROR(ERR_CLT_OBJECT_IS_NULL, "connection");
return NULL;
}
if (conn->error_code == ERR_ERRNO_BASE) {
clt_copy_local_error(conn);
}
return conn->message;
}
uint32 ogconn_get_sid(ogconn_conn_t pconn)
{
clt_conn_t *conn = (clt_conn_t *)pconn;
return (conn != NULL) ? conn->sid : OG_INVALID_ID32;
}
void ogconn_set_paramset_size(ogconn_stmt_t pstmt, uint32 sz)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
if (SECUREC_UNLIKELY(stmt == NULL)) {
OG_THROW_ERROR(ERR_CLT_OBJECT_IS_NULL, "statement");
return;
}
stmt->paramset_size = sz;
}
status_t ogconn_datetime_construct(ogconn_stmt_t pstmt, ogconn_datetime_t datetime, int32 datatype, uint16 year, uint8
mon,
uint8 day, uint8 hour, uint8 min, uint8 sec, uint32 fsec, char *timezone, uint32 timezone_len)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
date_detail_t date_detail = { 0 };
text_t timezone_txt = {
.str = timezone,
.len = timezone_len
};
date_t encode_date;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, datetime, "datetime");
if (!CM_IS_VALID_YEAR(year)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "input year", (uint32)year);
return OG_ERROR;
}
if (!CM_IS_VALID_MONTH(mon)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "input month", (uint32)mon);
return OG_ERROR;
}
if (!CM_IS_VALID_DAY(day)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "input day", (uint32)day);
return OG_ERROR;
}
if (!CM_IS_VALID_HOUR(hour)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "input hour", (uint32)hour);
return OG_ERROR;
}
if (!CM_IS_VALID_MINUTE(min)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "input minute", (uint32)min);
return OG_ERROR;
}
if (!CM_IS_VALID_SECOND(sec)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "input second", (uint32)sec);
return OG_ERROR;
}
if (!CM_IS_VALID_FRAC_SEC(fsec)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "input nano second", (uint32)fsec);
return OG_ERROR;
}
date_detail.year = year;
date_detail.mon = mon;
date_detail.day = day;
date_detail.hour = hour;
date_detail.min = min;
date_detail.sec = sec;
date_detail.millisec = fsec / NANOSECS_PER_MILLISEC;
date_detail.microsec = (fsec % NANOSECS_PER_MILLISEC) / NANOSECS_PER_MICROSEC;
date_detail.nanosec = fsec % NANOSECS_PER_MICROSEC;
encode_date = cm_encode_date(&date_detail);
switch (datatype) {
case OGCONN_TYPE_TIMESTAMP_TZ_FAKE:
case OGCONN_TYPE_TIMESTAMP:
*(timestamp_t *)datetime = encode_date;
break;
case OGCONN_TYPE_TIMESTAMP_LTZ:
*(timestamp_ltz_t *)datetime = cm_adjust_date_between_two_tzs((timestamp_ltz_t)encode_date,
stmt->conn->local_sessiontz, stmt->conn->server_info.server_dbtimezone);
break;
case OGCONN_TYPE_TIMESTAMP_TZ:
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, timezone, "timezone");
OG_RETURN_IFERR(cm_text2tzoffset(&timezone_txt, &date_detail.tz_offset));
((timestamp_tz_t *)datetime)->tstamp = encode_date;
((timestamp_tz_t *)datetime)->tz_offset = date_detail.tz_offset;
break;
default:
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "timestamp type", (uint32)datatype);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t ogconn_datetime_deconstruct(ogconn_stmt_t pstmt, ogconn_datetime_t datetime, int32 datatype, uint16 *year,
uint8 *mon,
uint8 *day, uint8 *hour, uint8 *min, uint8 *sec, uint32 *fsec)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
date_detail_t date_detail = { 0 };
date_t timeinfo = 0;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, datetime, "datetime");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, year, "year");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, mon, "mon");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, day, "day");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, hour, "hour");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, min, "min");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, sec, "sec");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, fsec, "fsec");
switch (datatype) {
case OGCONN_TYPE_TIMESTAMP_TZ_FAKE:
case OGCONN_TYPE_TIMESTAMP:
case OGCONN_TYPE_TIMESTAMP_LTZ:
timeinfo = *(timestamp_t *)datetime;
break;
case OGCONN_TYPE_TIMESTAMP_TZ:
timeinfo = ((timestamp_tz_t *)datetime)->tstamp;
break;
default:
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "timestamp type", (uint32)datatype);
return OG_ERROR;
}
cm_decode_date(timeinfo, &date_detail);
*year = date_detail.year;
*mon = date_detail.mon;
*day = date_detail.day;
*hour = date_detail.hour;
*min = date_detail.min;
*sec = date_detail.sec;
*fsec = date_detail.millisec * NANOSECS_PER_MILLISEC + date_detail.microsec * NANOSECS_PER_MICROSEC +
date_detail.nanosec;
return OG_SUCCESS;
}
status_t ogconn_datetime_get_timezone_name(ogconn_stmt_t pstmt, ogconn_datetime_t datetime, int32 datatype, char *buf,
uint32 *buf_len)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
timezone_info_t timezone_info = 0;
text_t timezone_txt = {
.str = buf,
.len = 0
};
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, datetime, "datetime");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, buf, "buf");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, buf_len, "buf_len");
switch (datatype) {
case OGCONN_TYPE_TIMESTAMP_TZ:
timezone_info = ((timestamp_tz_t *)datetime)->tz_offset;
break;
case OGCONN_TYPE_TIMESTAMP_LTZ:
timezone_info = stmt->conn->local_sessiontz;
break;
default:
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "timestamp type", (uint32)datatype);
return OG_ERROR;
}
if (*buf_len < TIMEZONE_OFFSET_STRLEN) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_STRING_BUF_TOO_SMALL, "time zone buffer", *buf_len);
return OG_ERROR;
}
OG_RETURN_IFERR(cm_tzoffset2text(timezone_info, &timezone_txt));
*buf_len = timezone_txt.len;
return OG_SUCCESS;
}
status_t ogconn_datetime_get_timezone_offset(ogconn_stmt_t pstmt, ogconn_datetime_t datetime, int32 datatype, int8
*hour,
int8 *min)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
timezone_info_t timezone_info = 0;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, datetime, "datetime");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, hour, "hour");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, min, "min");
switch (datatype) {
case OGCONN_TYPE_TIMESTAMP_TZ:
timezone_info = ((timestamp_tz_t *)datetime)->tz_offset;
break;
case OGCONN_TYPE_TIMESTAMP_LTZ:
timezone_info = stmt->conn->local_sessiontz;
break;
default:
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "timestamp type", (uint32)datatype);
return OG_ERROR;
}
*hour = (int8)TIMEZONE_GET_HOUR(timezone_info);
*min = (int8)TIMEZONE_GET_SIGN_MINUTE(timezone_info);
return OG_SUCCESS;
}
static inline status_t clt_per_bind_info(clt_stmt_t *stmt, int type, const void *data, int32 *size)
{
switch (type) {
case OGCONN_TYPE_INTEGER:
case OGCONN_TYPE_UINT32:
case OGCONN_TYPE_BOOLEAN:
*size = sizeof(int32);
break;
case OGCONN_TYPE_BIGINT:
case OGCONN_TYPE_TIMESTAMP:
case OGCONN_TYPE_TIMESTAMP_TZ_FAKE:
case OGCONN_TYPE_TIMESTAMP_LTZ:
case OGCONN_TYPE_NATIVE_DATE:
*size = sizeof(int64);
break;
case OGCONN_TYPE_REAL:
*size = sizeof(double);
break;
case OGCONN_TYPE_NUMBER2:
case OGCONN_TYPE_NUMBER:
case OGCONN_TYPE_DECIMAL:
case OGCONN_TYPE_CHAR:
case OGCONN_TYPE_VARCHAR:
case OGCONN_TYPE_STRING:
case OGCONN_TYPE_BINARY:
case OGCONN_TYPE_VARBINARY:
case OGCONN_TYPE_RAW:
length of its content, thus these spaces should be considered.
string value putted into send-pack,include body(align 4) and length */
break;
case OGCONN_TYPE_DATE:
*size = CLT_DATE_BINARY_SIZE;
break;
case OGCONN_TYPE_TIMESTAMP_TZ:
*size = sizeof(timestamp_tz_t);
break;
case OGCONN_TYPE_INTERVAL_YM:
*size = sizeof(interval_ym_t);
break;
case OGCONN_TYPE_INTERVAL_DS:
*size = sizeof(interval_ds_t);
break;
case OGCONN_TYPE_CLOB:
case OGCONN_TYPE_BLOB:
case OGCONN_TYPE_IMAGE:
case OGCONN_TYPE_ARRAY:
clt_reset_batch_lob((ogconn_lob_t *)data, stmt->paramset_size);
*size = sizeof(ogconn_lob_t);
break;
default:
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_BIND, "bind type not supports");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t clt_bind_by_pos2(clt_stmt_t *stmt, uint32 pos, int type, const void *data, int32 size, uint16 *ind,
int32 direction)
{
clt_param_t *param = NULL;
if (SECUREC_UNLIKELY(stmt->status < CLI_STMT_PREPARED)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "sql is not prepared");
return OG_ERROR;
}
if (SECUREC_UNLIKELY(pos >= stmt->param_count || pos >= stmt->params.count)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_INDEX, "parameter");
return OG_ERROR;
}
if (SECUREC_UNLIKELY(!OGCONN_IS_DATABASE_DATATYPE(type))) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "data type", (uint32)type);
return OG_ERROR;
}
if (SECUREC_UNLIKELY(direction < OGCONN_INPUT || direction > OGCONN_INOUT)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_BIND, "direction only supports OGCONN_INPUT/OGCONN_OUT/OGCONN_INOUT");
return OG_ERROR;
}
OG_RETURN_IFERR(clt_per_bind_info(stmt, type, data, &size));
param = (clt_param_t *)cm_list_get(&stmt->params, pos);
param->direction = direction;
param->bnd_type = type;
param->bnd_size = size;
param->bnd_ptr = (char *)data;
param->ind_ptr = ind;
param->curr_ptr = NULL;
param->is_W_CType = OG_FALSE;
return OG_SUCCESS;
}
status_t ogconn_bind_by_pos2(ogconn_stmt_t pstmt, uint32 pos, int type, const void *data, int32 size, uint16 *ind,
int32 direction)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_bind_by_pos2(stmt, pos, type, data, size, ind, direction);
clt_unlock_conn(stmt->conn);
return status;
}
status_t ogconn_bind_by_pos(ogconn_stmt_t pstmt, uint32 pos, int type, const void *data, int32 size, uint16 *ind)
{
return ogconn_bind_by_pos2(pstmt, pos, type, data, size, ind, OGCONN_INPUT);
}
status_t ogconn_bind_value_len_by_pos(ogconn_stmt_t pstmt, uint32 pos, const void *data, uint16 *ind, bool32 is_trans,
bool32 ind_not_null)
{
clt_param_t *param = NULL;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
param = (clt_param_t *)cm_list_get(&stmt->params, pos);
if (is_trans) {
param->bnd_ptr = (char *)data;
}
if (ind_not_null) {
param->ind_ptr = ind;
}
clt_unlock_conn(stmt->conn);
return OG_SUCCESS;
}
status_t ogconn_sql_set_param_c_type(ogconn_stmt_t pstmt, uint32 pos, bool32 ctype)
{
clt_param_t *param = NULL;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
param = (clt_param_t *)cm_list_get(&stmt->params, pos);
param->is_W_CType = ctype;
clt_unlock_conn(stmt->conn);
return OG_SUCCESS;
}
static bool32 clt_is_bind_name_equal_ins(const char *name1, const char *name2)
{
char *str1 = (char *)name1;
char *str2 = (char *)name2;
if (str1[0] == ':') {
str1++;
}
if (str2[0] == ':') {
str2++;
}
return cm_str_equal_ins(str1, str2);
}
status_t ogconn_get_paramid_by_name(ogconn_stmt_t pstmt, const char *name, unsigned int offset1, unsigned int *pos)
{
clt_param_t *param = NULL;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
unsigned int offset = offset1;
OGCONN_CHECK_OBJECT_NULL_GS(pos, "position pointer");
for (uint32 i = 0; i < stmt->param_count && i < stmt->params.count; i++) {
param = (clt_param_t *)cm_list_get(&stmt->params, i);
if (!clt_is_bind_name_equal_ins(name, param->name)) {
continue;
}
if (offset > 0) {
offset--;
continue;
}
*pos = i;
return OG_SUCCESS;
}
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_ATTR, "parameter name", name);
return OG_ERROR;
}
static status_t clt_bind_by_name2(clt_stmt_t *stmt, const char *name, int32 type, const void *data, int32 size,
uint16 *ind, int32 direction)
{
uint32 i;
uint32 bnd_count = 0;
clt_param_t *param = NULL;
if (SECUREC_UNLIKELY(stmt->status < CLI_STMT_PREPARED)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "sql is not prepared");
return OG_ERROR;
}
for (i = 0; i < stmt->param_count && i < stmt->params.count; i++) {
param = (clt_param_t *)cm_list_get(&stmt->params, i);
if (!clt_is_bind_name_equal_ins(name, param->name)) {
continue;
}
OG_RETURN_IFERR(clt_bind_by_pos2(stmt, i, type, data, size, ind, direction));
bnd_count++;
}
if (bnd_count == 0) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_ATTR, "parameter name", name);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t ogconn_bind_by_name2(ogconn_stmt_t pstmt, const char *name, int type, const void *data, int32 size, uint16
*ind,
int32 direction)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, name, "name");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_bind_by_name2(stmt, name, type, data, size, ind, direction);
clt_unlock_conn(stmt->conn);
return status;
}
status_t ogconn_bind_by_name(ogconn_stmt_t pstmt, const char *name, int type, const void *data, int32 size, uint16 *ind)
{
return ogconn_bind_by_name2(pstmt, name, type, data, size, ind, OGCONN_INPUT);
}
status_t ogconn_desc_column_by_id(ogconn_stmt_t pstmt, uint32 id, ogconn_column_desc_t *desc)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_desc_column_by_id(stmt, id, desc);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_desc_inner_column_by_id(clt_stmt_t *stmt, uint32 id, ogconn_inner_column_desc_t *desc)
{
clt_column_t *column = NULL;
if (SECUREC_UNLIKELY(id >= stmt->column_count)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_INDEX, "column");
return OG_ERROR;
}
if (desc != NULL) {
column = (clt_column_t *)cm_list_get(&stmt->columns, id);
desc->name = column->def.name;
desc->type = column->def.datatype;
desc->size = column->def.size;
desc->precision = column->def.precision;
desc->scale = column->def.scale;
desc->nullable = column->def.nullable;
desc->auto_increment = column->def.auto_increment;
desc->is_character = column->def.is_character;
desc->is_array = column->def.is_array;
desc->is_jsonb = column->def.is_jsonb;
desc->is_rowid_type = column->def.is_rowid_type;
}
return OG_SUCCESS;
}
status_t ogconn_desc_inner_column_by_id(ogconn_stmt_t pstmt, uint32 id, ogconn_inner_column_desc_t *desc)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_desc_inner_column_by_id(stmt, id, desc);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_desc_column_by_name(clt_stmt_t *stmt, const char *col_name, ogconn_column_desc_t *desc)
{
uint32 i;
clt_column_t *column = NULL;
for (i = 0; i < stmt->column_count && i < stmt->columns.count; i++) {
column = (clt_column_t *)cm_list_get(&stmt->columns, i);
if (cm_str_equal_ins(col_name, column->def.name)) {
if (SECUREC_LIKELY(desc != NULL)) {
desc->name = column->def.name;
desc->type = column->def.datatype;
desc->size = column->def.size;
desc->precision = column->def.precision;
desc->scale = column->def.scale;
desc->nullable = column->def.nullable;
desc->is_character = column->def.is_character;
}
return OG_SUCCESS;
}
}
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_ATTR, "column name", col_name);
return OG_ERROR;
}
status_t ogconn_desc_column_by_name(ogconn_stmt_t pstmt, const char *col_name, ogconn_column_desc_t *desc)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, col_name, "column name");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_desc_column_by_name(stmt, col_name, desc);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_get_desc_attr(clt_stmt_t *stmt, uint32 id, int32 attr, void *data, uint32 *len)
{
uint32 attr_len = 0;
clt_column_t *column = NULL;
if (SECUREC_UNLIKELY(id >= stmt->column_count)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_INDEX, "column");
return OG_ERROR;
}
column = (clt_column_t *)cm_list_get(&stmt->columns, id);
switch (attr) {
case OGCONN_ATTR_NAME:
attr_len = column->def.name_len;
*(char **)data = column->def.name;
break;
case OGCONN_ATTR_DATA_SIZE:
attr_len = sizeof(uint16);
*(uint16 *)data = column->def.size;
break;
case OGCONN_ATTR_PRECISION:
attr_len = sizeof(uint8);
*(uint8 *)data = column->def.precision;
break;
case OGCONN_ATTR_SCALE:
attr_len = sizeof(int8);
*(int8 *)data = column->def.scale;
break;
case OGCONN_ATTR_DATA_TYPE:
attr_len = sizeof(uint16);
*(uint16 *)data = column->def.datatype;
break;
case OGCONN_ATTR_NULLABLE:
attr_len = sizeof(uint8);
*(uint8 *)data = column->def.nullable;
break;
case OGCONN_ATTR_CHAR_USED:
attr_len = sizeof(uint8);
*(uint8 *)data = column->def.is_character;
break;
case OGCONN_ATTR_ARRAY_USED:
attr_len = sizeof(uint8);
*(uint8 *)data = column->def.is_array;
break;
default:
OG_THROW_ERROR(ERR_CLT_INVALID_VALUE, "describe attribute id", (uint32)attr);
return OG_ERROR;
}
if (len != NULL) {
*len = attr_len;
}
return OG_SUCCESS;
}
status_t ogconn_get_desc_attr(ogconn_stmt_t pstmt, uint32 id, int32 attr, void *data, uint32 *len)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, data, "value of statement attribute to get");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_get_desc_attr(stmt, id, attr, data, len);
clt_unlock_conn(stmt->conn);
return status;
}
status_t ogconn_get_column_count(ogconn_stmt_t pstmt, uint32 *column_count)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
if (SECUREC_LIKELY(column_count != NULL)) {
*column_count = stmt->column_count;
}
return OG_SUCCESS;
}
status_t ogconn_get_column_by_id(ogconn_stmt_t pstmt, unsigned int id, void **data, unsigned int *size, bool32 *is_null)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_get_column_by_id(stmt, id, data, size, is_null);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_get_column_by_name(clt_stmt_t *stmt, const char *col_name, void **data, uint32 *size,
uint32 *is_null)
{
uint32 i;
clt_column_t *column = NULL;
if (SECUREC_UNLIKELY(stmt->status < CLI_STMT_FETCHING)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "statement is not fetched");
return OG_ERROR;
}
for (i = 0; i < stmt->column_count && i < stmt->columns.count; i++) {
column = (clt_column_t *)cm_list_get(&stmt->columns, i);
if (cm_str_equal_ins(col_name, column->def.name)) {
if (SECUREC_LIKELY(size != NULL)) {
*size = column->size;
}
if (SECUREC_LIKELY(is_null != NULL)) {
*is_null = (column->size == OGCONN_NULL);
}
if (SECUREC_LIKELY(data != NULL)) {
*data = (column->size == OGCONN_NULL) ? NULL : ((column->bnd_ptr == NULL) ? column->ptr :
column->bnd_ptr);
}
return OG_SUCCESS;
}
}
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_ATTR, "column name", col_name);
return OG_ERROR;
}
status_t ogconn_get_column_by_name(ogconn_stmt_t pstmt, const char *col_name, void **data, uint32 *size, uint32
*is_null)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, col_name, "column name");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_get_column_by_name(stmt, col_name, data, size, is_null);
clt_unlock_conn(stmt->conn);
return status;
}
uint32 ogconn_get_affected_rows(ogconn_stmt_t pstmt)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
return (stmt != NULL) ? stmt->affected_rows : 0;
}
#define CLT_CHECK_AS_STR_SIZE(id, buf_size, need_size) \
{ \
if ((buf_size) < (need_size)) { \
CLT_THROW_ERROR(stmt->conn, ERR_CLT_COL_SIZE_TOO_SMALL, (uint32)(id), "as string", (uint32)(buf_size), \
(uint32)(need_size)); \
return OG_ERROR; \
} \
}
static status_t ogconn_column_as_string_get_data(clt_stmt_t *stmt, const clt_column_t *column, char *str, uint32 buf_size,
uint32 tsize, void *data)
{
int32 int_value;
uint32 uint_value;
uint32 size = tsize;
int64 bigint_value;
double real_value;
uint32 num_width;
timestamp_tz_t tstz;
uint32 read_size;
text_t fmt_text;
binary_t bin;
int32 iret_snprintf;
dec4_t dec4;
dec2_t dec2;
switch (column->def.datatype) {
case OGCONN_TYPE_INTEGER:
int_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int32(*(int32 *)data) : *(int32 *)data;
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, PRINT_FMT_INTEGER, int_value));
break;
case OGCONN_TYPE_UINT32:
uint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_uint32(*(uint32 *)data) : *(uint32 *)data;
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, PRINT_FMT_UINT32, uint_value));
break;
case OGCONN_TYPE_BIGINT:
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, PRINT_FMT_BIGINT, bigint_value));
break;
case OGCONN_TYPE_REAL:
real_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_real(*(double *)data) : *(double *)data;
CM_SNPRINTF_REAL(iret_snprintf, str, real_value, buf_size);
PRTS_RETURN_IFERR(iret_snprintf);
break;
case OGCONN_TYPE_NUMBER2:
num_width = MIN(stmt->conn->num_width + 1, buf_size);
cm_dec2_copy_ex(&dec2, (const payload_t *)data, (uint8)size);
if (cm_dec2_to_str(&dec2, num_width, str) != OG_SUCCESS) {
if (num_width > 1) {
MEMS_RETURN_IFERR(memset_s(str, num_width - 1, '#', num_width - 1));
}
str[num_width - 1] = '\0';
}
break;
case OGCONN_TYPE_NUMBER:
case OGCONN_TYPE_DECIMAL:
if (CS_DIFFERENT_ENDIAN(stmt->conn->pack.options)) {
cm_reverse_dec4(&dec4, (dec4_t *)data);
} else {
dec4 = *(dec4_t *)data;
}
num_width = MIN(stmt->conn->num_width + 1, buf_size);
if (cm_dec4_to_str(&dec4, num_width, str) != OG_SUCCESS) {
if (num_width > 1) {
MEMS_RETURN_IFERR(memset_s(str, num_width - 1, '#', num_width - 1));
}
str[num_width - 1] = '\0';
}
break;
case OGCONN_TYPE_BOOLEAN:
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, OGCONN_BOOL_BOUND_SIZE);
int_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int32(*(int32 *)data) : *(int32 *)data;
(void)cm_bool2str((bool32)int_value, str);
break;
case OGCONN_TYPE_DATE:
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, OGCONN_TIME_BOUND_SIZE);
clt_session_nlsparam_geter(stmt, NLS_DATE_FORMAT, &fmt_text);
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, fmt_text.len + 1);
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
return cm_date2str_ex((date_t)bigint_value, &fmt_text, str, buf_size);
case OGCONN_TYPE_TIMESTAMP:
case OGCONN_TYPE_TIMESTAMP_TZ_FAKE:
case OGCONN_TYPE_TIMESTAMP_LTZ:
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, OGCONN_TIME_BOUND_SIZE);
clt_session_nlsparam_geter(stmt, NLS_TIMESTAMP_FORMAT, &fmt_text);
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, fmt_text.len + 7);
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
return cm_timestamp2str_ex((timestamp_t)bigint_value, &fmt_text, column->def.precision, str, buf_size);
case OGCONN_TYPE_TIMESTAMP_TZ:
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, OGCONN_TIME_BOUND_SIZE);
clt_session_nlsparam_geter(stmt, NLS_TIMESTAMP_TZ_FORMAT, &fmt_text);
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, fmt_text.len + 7);
tstz.tstamp = CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ?
cs_reverse_int64(((timestamp_tz_t *)data)->tstamp) :
((timestamp_tz_t *)data)->tstamp;
tstz.tz_offset = CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ?
cs_reverse_int16(((timestamp_tz_t *)data)->tz_offset) :
((timestamp_tz_t *)data)->tz_offset;
return cm_timestamp_tz2str_ex(&tstz, &fmt_text, column->def.precision, str, buf_size);
case OGCONN_TYPE_INTERVAL_YM:
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, OGCONN_YM_INTERVAL_BOUND_SIZE);
int_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int32(*(int32 *)data) : *(int32 *)data;
(void)cm_yminterval2str_ex((interval_ym_t)int_value, column->def.precision, str);
break;
case OGCONN_TYPE_INTERVAL_DS:
CLT_CHECK_AS_STR_SIZE(column->id, buf_size, OGCONN_DS_INTERVAL_BOUND_SIZE);
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
(void)cm_dsinterval2str_ex((interval_ds_t)bigint_value, column->def.precision, column->def.scale, str,
buf_size);
break;
case OGCONN_TYPE_CHAR:
case OGCONN_TYPE_VARCHAR:
case OGCONN_TYPE_STRING:
case OGCONN_TYPE_BINARY:
case OGCONN_TYPE_VARBINARY:
size = (size >= buf_size - 1) ? buf_size - 1 : size;
if (size != 0) {
MEMS_RETURN_IFERR(memcpy_s(str, buf_size, data, size));
}
str[size] = '\0';
break;
case OGCONN_TYPE_RAW:
bin.bytes = (uint8 *)data;
bin.size = size;
return cm_bin2str(&bin, OG_FALSE, str, buf_size);
case OGCONN_TYPE_CLOB:
return clt_clob_as_string(stmt, data, str, buf_size, &read_size);
case OGCONN_TYPE_BLOB:
return clt_blob_as_string(stmt, data, str, buf_size, &read_size);
case OGCONN_TYPE_IMAGE:
return clt_image_as_string(stmt, data, str, buf_size, &read_size);
default:
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, "<UNKNOWN TYPE>"));
break;
}
return OG_SUCCESS;
}
static status_t clt_element_as_string(clt_stmt_t *stmt, clt_array_assist_t *aa, const char *data, uint32 data_len,
uint32 *full, uint32 array_format)
{
int ret;
uint32 free;
char *last_str = CLT_ARRAY_MORE_ELE_FOR_DISPLAY;
free = aa->dst_len - aa->dst_offset;
if (free <= data_len + strlen(last_str)) {
*full = OG_TRUE;
if (array_format == ARRAY_USE_SQUARE_BRACKET) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_BUF_SIZE_TOO_SMALL,
"to export Array data with \'filetype=txt\', Please use \'filetype=bin\'");
return OG_ERROR;
} else {
ret = strncpy_sp(aa->dst + aa->dst_offset, free, last_str, strlen(last_str));
if (ret != EOK) {
CLT_THROW_ERROR(stmt->conn, ERR_SYSTEM_CALL, ret);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
ret = strncpy_sp(aa->dst + aa->dst_offset, free, data, data_len);
if (ret != EOK) {
CLT_THROW_ERROR(stmt->conn, ERR_SYSTEM_CALL, ret);
*full = OG_TRUE;
return OG_ERROR;
}
aa->dst_offset += data_len;
return OG_SUCCESS;
}
static status_t clt_gen_array_prefix(clt_stmt_t *stmt, clt_array_assist_t *aa, uint32 *full, uint32 subscript,
uint32 array_format)
{
if (array_format == ARRAY_USE_SQUARE_BRACKET) {
int len = strlen(CLT_ARRAY_PRE_FOR_EXP);
uint32 free = aa->dst_len - aa->dst_offset;
int ret = strncpy_sp(aa->dst + aa->dst_offset, free, CLT_ARRAY_PRE_FOR_EXP, len);
if (ret != EOK) {
CLT_THROW_ERROR(stmt->conn, ERR_SYSTEM_CALL, ret);
*full = OG_TRUE;
return OG_ERROR;
}
aa->dst_offset += len;
} else {
aa->dst[aa->dst_offset++] = CLT_ARRAY_PRE_FOR_DISPLAY;
}
aa->expect_subscript = subscript + 1;
return OG_SUCCESS;
}
static status_t clt_gen_null_or_empty_ele(char *col_value, uint32 offset, uint32 array_format)
{
if (offset == ELEMENT_NULL_OFFSET) {
if (strncpy_sp(col_value, OG_MAX_COLUMN_SIZE, "NULL", strlen("NULL")) != EOK) {
return OG_ERROR;
}
} else {
if (array_format == ARRAY_USE_SQUARE_BRACKET) {
if (strncpy_sp(col_value, OG_MAX_COLUMN_SIZE, "'\"\"'", strlen("'\"\"'")) != EOK) {
return OG_ERROR;
}
} else {
if (strncpy_sp(col_value, OG_MAX_COLUMN_SIZE, "\"\"", strlen("\"\"")) != EOK) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t clt_gen_ele_with_single_quote(clt_stmt_t *stmt, char **elem, char *local_buf)
{
bool32 exist_flag = OG_FALSE;
uint32 max_len = OG_MAX_COLUMN_SIZE + 1;
uint32 len;
2) elem[0] or local_buf[0] is reversed for single quote which is used for mark border
3) the max buf len of 'local_buf + 1' should be CLT_MAX_LEN_WITH_SINGLE_QUOTE_MARK2 */
OG_RETURN_IFERR(cm_replace_quotation(*elem + 1, local_buf + 1, CLT_MAX_LEN_WITH_SINGLE_QUOTE_MARK2, &exist_flag));
if (exist_flag) {
*elem = local_buf;
max_len = CLT_MAX_LEN_WITH_SINGLE_QUOTE_MARK2 - 1;
}
(*elem)[0] = '\'';
len = strlen(*elem);
if (len > max_len) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "array element size", len);
return OG_ERROR;
}
(*elem)[len] = '\'';
(*elem)[len + 1] = '\0';
return OG_SUCCESS;
}
static status_t clt_elements_as_string(clt_stmt_t *stmt, const clt_column_t *column, elem_dir_t *dir,
clt_array_assist_t *aa, uint32 *full, uint32 array_format)
{
uint32 nbytes;
uint32 subscript;
uint32 size;
uint32 offset;
bool32 eof = OG_FALSE;
bool32 need_convert = CS_DIFFERENT_ENDIAN(stmt->conn->pack.options);
char col_value[CLT_MAX_LEN_WITH_SINGLE_QUOTE_MARK + 1] = { 0 };
char local_buf[CLT_MAX_LEN_WITH_SINGLE_QUOTE_MARK2 + 1] = { 0 };
char *elem = col_value;
size = need_convert ? cs_reverse_uint32(dir->size) : dir->size;
subscript = need_convert ? cs_reverse_uint32(dir->subscript) : dir->subscript;
offset = need_convert ? cs_reverse_uint32(dir->offset) : dir->offset;
if (aa->expect_subscript == OG_INVALID_ID32) {
OG_RETURN_IFERR(clt_gen_array_prefix(stmt, aa, full, subscript, array_format));
} else {
2) For export: array output format : array['val1','val2',...] */
while (subscript > aa->expect_subscript) {
OG_RETURN_IFERR(clt_element_as_string(stmt, aa, ",NULL", (uint32)strlen(",NULL"), full, array_format));
if (*full == OG_TRUE) {
return OG_SUCCESS;
}
aa->expect_subscript++;
}
aa->dst[aa->dst_offset++] = ',';
aa->expect_subscript++;
}
if (size == 0) {
OG_RETURN_IFERR(clt_gen_null_or_empty_ele(elem, offset, array_format));
} else {
OG_RETURN_IFERR(clt_read_blob(stmt, aa->locator, offset, aa->ele_val, size, &nbytes, &eof));
if (nbytes != size) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "array element size", size);
return OG_ERROR;
}
if (array_format == ARRAY_USE_SQUARE_BRACKET) {
OG_RETURN_IFERR(
ogconn_column_as_string_get_data(stmt, column, elem + 1, OG_MAX_COLUMN_SIZE + 1, size, aa->ele_val));
OG_RETURN_IFERR(clt_gen_ele_with_single_quote(stmt, &elem, local_buf));
} else {
OG_RETURN_IFERR(
ogconn_column_as_string_get_data(stmt, column, elem, OG_MAX_COLUMN_SIZE + 1, size, aa->ele_val));
}
}
return clt_element_as_string(stmt, aa, elem, (uint32)strlen(elem), full, array_format);
}
static status_t clt_get_dir(clt_stmt_t *stmt, void *locator, elem_dir_t *dir, uint32 dir_size)
{
uint32 nbytes;
uint32 eof;
uint32 offset = sizeof(array_head_t);
uint32 remain = dir_size;
while (remain > 0) {
if (clt_read_blob(stmt, locator, offset, (char *)dir + (dir_size - remain), remain, &nbytes, &eof) !=
OG_SUCCESS) {
free(dir);
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "array elements' size", dir_size);
return OG_ERROR;
}
remain -= nbytes;
offset += nbytes;
}
return OG_SUCCESS;
}
static status_t clt_array_as_string_inner(clt_stmt_t *stmt, void *locator, const clt_column_t *column, char *str,
uint32 buf_size, uint32 array_format)
{
uint32 i;
uint32 nbytes;
uint32 dir_size;
uint32 eof = OG_FALSE;
uint32 full = OG_FALSE;
char data[OG_MAX_COLUMN_SIZE + 1] = { 0 };
char *end_array = ((array_format == ARRAY_USE_BRACE) ? CLT_ARRAY_END_FOR_DISPLAY : CLT_ARRAY_END_FOR_EXP);
char *null_array = ((array_format == ARRAY_USE_BRACE) ? CLT_ARRAY_NULL_FOR_DISPLAY : CLT_ARRAY_NULL_FOR_EXP);
clt_array_assist_t aa;
elem_dir_t *dir = NULL;
errno_t errcode;
array_head_t head;
OG_RETURN_IFERR(clt_read_blob(stmt, locator, 0, (void *)&head, sizeof(head), &nbytes, &eof));
if (head.count == 0) {
MEMS_RETURN_IFERR(memcpy_sp(str, buf_size, null_array, strlen(null_array) + 1));
return OG_SUCCESS;
}
dir_size = head.count * sizeof(elem_dir_t);
dir = (elem_dir_t *)malloc(dir_size);
if (dir == NULL) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_TOO_MANY_ELEMENTS);
return OG_ERROR;
}
OG_RETURN_IFERR(clt_get_dir(stmt, locator, dir, dir_size));
aa.ele_val = data;
aa.dst = str;
aa.dst_len = buf_size;
aa.dst_offset = 0;
aa.expect_subscript = OG_INVALID_ID32;
aa.locator = locator;
for (i = 0; i < head.count; i++) {
if (clt_elements_as_string(stmt, column, dir + i, &aa, &full, array_format) != OG_SUCCESS) {
free(dir);
return OG_ERROR;
}
OG_BREAK_IF_TRUE(full);
if (i == head.count - 1) {
errcode = strncpy_s(aa.dst + aa.dst_offset, (uint32)(aa.dst_len - aa.dst_offset), end_array, 1);
if (errcode != EOK) {
free(dir);
OG_THROW_ERROR(ERR_SYSTEM_CALL, errcode);
return OG_ERROR;
}
aa.dst[++aa.dst_offset] = '\0';
}
}
free(dir);
return OG_SUCCESS;
}
static status_t clt_array_as_string(clt_stmt_t *stmt, void *locator, const clt_column_t *column, char *str,
uint32 buf_size, uint32 array_format)
{
char *null_array = ((array_format == ARRAY_USE_BRACE) ? CLT_ARRAY_NULL_FOR_DISPLAY : CLT_ARRAY_NULL_FOR_EXP);
if (buf_size < strlen(null_array) + 1) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_COL_SIZE_TOO_SMALL, column->id, "as string", buf_size, strlen(null_array));
return OG_ERROR;
}
if (stmt->conn->autotrace) {
*(uint32 *)str = CLT_ARRAY_MORE;
return OG_SUCCESS;
}
if (column->size == 0) {
MEMS_RETURN_IFERR(memcpy_sp(str, buf_size, null_array, strlen(null_array) + 1));
return OG_SUCCESS;
}
return clt_array_as_string_inner(stmt, locator, column, str, buf_size, array_format);
}
static status_t clt_column_as_string(clt_stmt_t *stmt, uint32 id, char *str, uint32 buf_size, uint32 array_format)
{
void *data = NULL;
uint32 size;
uint32 is_null;
const clt_column_t *column = NULL;
if (SECUREC_UNLIKELY(stmt->status < CLI_STMT_FETCHING)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "statement is not fetched");
return OG_ERROR;
}
if (SECUREC_UNLIKELY(id >= stmt->column_count || id >= stmt->columns.count)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_INDEX, "column");
return OG_ERROR;
}
if (SECUREC_UNLIKELY(str == NULL || buf_size <= 1)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_STRING_BUF_TOO_SMALL, "column", id);
return OG_ERROR;
}
str[0] = '\0';
column = (clt_column_t *)cm_list_get(&stmt->columns, id);
is_null = (column->size == OGCONN_NULL);
data = column->ptr;
size = column->size;
if (is_null) {
if (column->def.datatype == OGCONN_TYPE_CURSOR) {
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, "CURSOR STATEMENT"));
}
return OG_SUCCESS;
}
if (column->def.is_array == OG_TRUE) {
return clt_array_as_string(stmt, data, column, str, buf_size, array_format);
}
return ogconn_column_as_string_get_data(stmt, column, str, buf_size, size, data);
}
status_t ogconn_column_as_string(ogconn_stmt_t pstmt, uint32 id, char *str, uint32 buf_size)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_column_as_string(stmt, id, str, buf_size, ARRAY_USE_BRACE);
clt_unlock_conn(stmt->conn);
return status;
}
status_t ogconn_column_as_array(ogconn_stmt_t pstmt, uint32 id, char *str, uint32 buf_size)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_column_as_string(stmt, id, str, buf_size, ARRAY_USE_SQUARE_BRACKET);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_bind_column(clt_stmt_t *stmt, uint32 id, uint16 bind_type, uint16 bind_size, void *bind_ptr,
uint16 *ind_ptr)
{
clt_column_t *column = NULL;
if (SECUREC_UNLIKELY(stmt->status < CLI_STMT_PREPARED)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "statement is not prepared");
return OG_ERROR;
}
if (SECUREC_UNLIKELY(id >= stmt->column_count || id >= stmt->columns.count)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_INDEX, "column");
return OG_ERROR;
}
column = (clt_column_t *)cm_list_get(&stmt->columns, id);
if (!(bind_type == column->def.datatype || OGCONN_IS_STRING_TYPE(bind_type) || OGCONN_IS_BINARY_TYPE(bind_type) ||
(OGCONN_IS_DATE_TYPE(bind_type) &&
(OGCONN_IS_DATE_TYPE(column->def.datatype) || OGCONN_IS_STRING_TYPE(column->def.datatype))) ||
(OGCONN_IS_NUMBER_TYPE(bind_type) &&
(OGCONN_IS_NUMBER_TYPE(column->def.datatype) || OGCONN_IS_STRING_TYPE(column->def.datatype))))) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_BIND, "bind type do not match with column type");
return OG_ERROR;
}
column->bnd_type = (uint8)bind_type;
column->bnd_size = bind_size;
column->bnd_ptr = (char *)bind_ptr;
column->ind_ptr = ind_ptr;
return OG_SUCCESS;
}
status_t ogconn_bind_column(ogconn_stmt_t pstmt, uint32 id, uint16 bind_type, uint16 bind_size, void *bind_ptr,
uint16 *ind_ptr)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_bind_column(stmt, id, bind_type, bind_size, bind_ptr, ind_ptr);
clt_unlock_conn(stmt->conn);
return status;
}
ogconn_stmt_t ogconn_get_query_stmt(ogconn_conn_t pconn)
{
clt_conn_t *conn = (clt_conn_t *)pconn;
return (conn != NULL) ? (ogconn_stmt_t)conn->query.query_stmt : NULL;
}
static status_t clt_get_implicit_resultset(clt_stmt_t *stmt, ogconn_stmt_t *resultset)
{
clt_stmt_t *sub_stmt = NULL;
uint32 *id = NULL;
clt_rs_stmt_t *rs_stmt = NULL;
*resultset = NULL;
if (stmt->resultset.pos + 1 > stmt->resultset.stmt_ids.count) {
return OG_SUCCESS;
}
OG_RETURN_IFERR(clt_alloc_stmt(stmt->conn, &sub_stmt));
rs_stmt = (clt_rs_stmt_t *)cm_list_get(&stmt->resultset.stmt_ids, stmt->resultset.pos);
sub_stmt->stmt_id = rs_stmt->stmt_id;
sub_stmt->fetch_mode = rs_stmt->fetch_mode;
if (clt_prepare_stmt_pack(sub_stmt) != OG_SUCCESS || clt_remote_fetch(sub_stmt) != OG_SUCCESS) {
clt_free_stmt(sub_stmt);
return OG_ERROR;
}
sub_stmt->status = CLI_STMT_EXECUTED;
sub_stmt->fetch_mode = 0;
if (cm_list_new(&stmt->resultset.ids, (void **)&id) != OG_SUCCESS) {
clt_free_stmt(sub_stmt);
return OG_ERROR;
}
*id = (uint32)sub_stmt->id;
*resultset = (ogconn_stmt_t)sub_stmt;
stmt->resultset.pos++;
return OG_SUCCESS;
}
status_t ogconn_get_implicit_resultset(ogconn_stmt_t pstmt, ogconn_stmt_t *resultset)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, resultset, "resultset");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_get_implicit_resultset(stmt, resultset);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_desc_outparam_by_id(clt_stmt_t *stmt, uint32 id, ogconn_outparam_desc_t *desc)
{
clt_outparam_t *outparam = NULL;
if (SECUREC_UNLIKELY(stmt->status < CLI_STMT_PREPARED)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "sql is not prepared");
return OG_ERROR;
}
if (SECUREC_UNLIKELY(id >= stmt->outparam_count || id >= stmt->outparams.count)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_INDEX, "outparam");
return OG_ERROR;
}
outparam = (clt_outparam_t *)cm_list_get(&stmt->outparams, id);
desc->name = outparam->def.name;
desc->size = outparam->def.size;
desc->direction = outparam->def.direction;
desc->type = outparam->def.datatype;
return OG_SUCCESS;
}
status_t ogconn_desc_outparam_by_id(ogconn_stmt_t pstmt, uint32 id, ogconn_outparam_desc_t *desc)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, desc, "desc");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_desc_outparam_by_id(stmt, id, desc);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_desc_outparam_by_name(clt_stmt_t *stmt, const char *name, ogconn_outparam_desc_t *desc)
{
clt_outparam_t *outparam = NULL;
uint32 i;
if (SECUREC_UNLIKELY(stmt->status < CLI_STMT_PREPARED)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "sql is not prepared");
return OG_ERROR;
}
for (i = 0; i < stmt->outparam_count && i < stmt->outparams.count; i++) {
outparam = (clt_outparam_t *)cm_list_get(&stmt->outparams, i);
if (cm_str_equal_ins(name, outparam->def.name)) {
desc->name = outparam->def.name;
desc->size = outparam->def.size;
desc->direction = outparam->def.direction;
desc->type = outparam->def.datatype;
return OG_SUCCESS;
}
}
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_ATTR, "outparam name", name);
return OG_ERROR;
}
status_t ogconn_desc_outparam_by_name(ogconn_stmt_t pstmt, const char *name, ogconn_outparam_desc_t *desc)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, name, "name");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, desc, "desc");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_desc_outparam_by_name(stmt, name, desc);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t ogconn_outparam_as_string_get_data(clt_stmt_t *stmt, uint32 id, char *str, uint32 buf_size,
const clt_outparam_t *outparam, uint32 tsize, void *data)
{
int32 int_value;
int64 bigint_value;
double real_value;
uint32 num_width;
timestamp_tz_t tstz;
uint32 read_size;
uint32 size = tsize;
text_t fmt_text;
binary_t bin;
int32 iret_snprintf;
dec2_t dec2;
switch (outparam->def.datatype) {
case OGCONN_TYPE_UINT32:
int_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_uint32(*(uint32 *)data) : *(uint32 *)data;
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, PRINT_FMT_UINT32, (uint32)int_value));
break;
case OGCONN_TYPE_INTEGER:
int_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int32(*(int32 *)data) : *(int32 *)data;
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, PRINT_FMT_INTEGER, int_value));
break;
case OGCONN_TYPE_BIGINT:
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, PRINT_FMT_BIGINT, bigint_value));
break;
case OGCONN_TYPE_REAL:
real_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_real(*(double *)data) : *(double *)data;
CM_SNPRINTF_REAL(iret_snprintf, str, real_value, buf_size);
PRTS_RETURN_IFERR(iret_snprintf);
break;
case OGCONN_TYPE_NUMBER2:
num_width = MIN(stmt->conn->num_width + 1, buf_size);
cm_dec2_copy_ex(&dec2, (const payload_t *)data, (uint8)size);
if (cm_dec2_to_str(&dec2, num_width, str) != OG_SUCCESS) {
if (num_width != 0) {
MEMS_RETURN_IFERR(memset_s(str, num_width, '#', num_width));
}
str[num_width] = '\0';
}
break;
case OGCONN_TYPE_NUMBER:
case OGCONN_TYPE_DECIMAL: {
num_width = MIN(stmt->conn->num_width, buf_size - 1);
if (cm_dec4_to_str((dec4_t *)data, num_width, str) != OG_SUCCESS) {
if (num_width != 0) {
MEMS_RETURN_IFERR(memset_s(str, num_width, '#', num_width));
}
str[num_width] = '\0';
}
break;
}
case OGCONN_TYPE_BOOLEAN:
CLT_CHECK_AS_STR_SIZE(id, buf_size, OGCONN_BOOL_BOUND_SIZE);
int_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int32(*(int32 *)data) : *(int32 *)data;
(void)cm_bool2str((bool32)int_value, str);
break;
case OGCONN_TYPE_DATE:
CLT_CHECK_AS_STR_SIZE(id, buf_size, OGCONN_TIME_BOUND_SIZE);
clt_session_nlsparam_geter(stmt, NLS_DATE_FORMAT, &fmt_text);
CLT_CHECK_AS_STR_SIZE(id, buf_size, fmt_text.len + 1);
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
return cm_date2str_ex((date_t)bigint_value, &fmt_text, str, buf_size);
case OGCONN_TYPE_TIMESTAMP:
case OGCONN_TYPE_TIMESTAMP_TZ_FAKE:
case OGCONN_TYPE_TIMESTAMP_LTZ:
CLT_CHECK_AS_STR_SIZE(id, buf_size, OGCONN_TIME_BOUND_SIZE);
clt_session_nlsparam_geter(stmt, NLS_TIMESTAMP_FORMAT, &fmt_text);
CLT_CHECK_AS_STR_SIZE(id, buf_size, fmt_text.len + 7);
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
return cm_timestamp2str_ex((timestamp_t)bigint_value, &fmt_text, OG_DEFAULT_DATETIME_PRECISION, str,
buf_size);
case OGCONN_TYPE_TIMESTAMP_TZ:
CLT_CHECK_AS_STR_SIZE(id, buf_size, OGCONN_TIME_BOUND_SIZE);
clt_session_nlsparam_geter(stmt, NLS_TIMESTAMP_TZ_FORMAT, &fmt_text);
CLT_CHECK_AS_STR_SIZE(id, buf_size, fmt_text.len + 1);
tstz.tstamp = CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ?
cs_reverse_int64(((timestamp_tz_t *)data)->tstamp) :
((timestamp_tz_t *)data)->tstamp;
tstz.tz_offset = CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ?
cs_reverse_int16(((timestamp_tz_t *)data)->tz_offset) :
((timestamp_tz_t *)data)->tz_offset;
return cm_timestamp_tz2str_ex(&tstz, &fmt_text, OG_DEFAULT_DATETIME_PRECISION, str, buf_size);
case OGCONN_TYPE_INTERVAL_YM:
CLT_CHECK_AS_STR_SIZE(id, buf_size, OGCONN_YM_INTERVAL_BOUND_SIZE);
int_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int32(*(int32 *)data) : *(int32 *)data;
(void)cm_yminterval2str((interval_ym_t)int_value, str);
break;
case OGCONN_TYPE_INTERVAL_DS:
CLT_CHECK_AS_STR_SIZE(id, buf_size, OGCONN_DS_INTERVAL_BOUND_SIZE);
bigint_value =
CS_DIFFERENT_ENDIAN(stmt->conn->pack.options) ? cs_reverse_int64(*(int64 *)data) : *(int64 *)data;
(void)cm_dsinterval2str((interval_ds_t)bigint_value, str, buf_size);
break;
case OGCONN_TYPE_CHAR:
case OGCONN_TYPE_VARCHAR:
case OGCONN_TYPE_STRING:
case OGCONN_TYPE_BINARY:
case OGCONN_TYPE_VARBINARY:
size = (size >= buf_size - 1) ? buf_size - 1 : size;
if (size != 0) {
MEMS_RETURN_IFERR(memcpy_s(str, buf_size, data, size));
}
str[size] = '\0';
break;
case OGCONN_TYPE_RAW:
bin.bytes = (uint8 *)data;
bin.size = size;
return cm_bin2str(&bin, OG_FALSE, str, buf_size);
case OGCONN_TYPE_CLOB:
return clt_clob_as_string(stmt, data, str, buf_size, &read_size);
case OGCONN_TYPE_BLOB:
return clt_blob_as_string(stmt, data, str, buf_size, &read_size);
case OGCONN_TYPE_IMAGE:
return clt_image_as_string(stmt, data, str, buf_size, &read_size);
case OGCONN_TYPE_CURSOR:
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, "SYS_REFCURSOR"));
break;
default:
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, "<UNKNOWN TYPE>"));
break;
}
return OG_SUCCESS;
}
static status_t clt_outparam_as_string_by_id(clt_stmt_t *stmt, uint32 id, char *str, uint32 buf_size)
{
void *data = NULL;
uint32 size = 0;
uint32 is_null = 0;
const clt_outparam_t *outparam = NULL;
if (SECUREC_UNLIKELY(str == NULL || buf_size <= 1)) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_STRING_BUF_TOO_SMALL, "outparam", id);
return OG_ERROR;
}
str[0] = '\0';
OG_RETURN_IFERR(clt_get_outparam_by_id(stmt, id, &data, &size, &is_null));
outparam = (clt_outparam_t *)cm_list_get(&stmt->outparams, id);
if (is_null) {
if (outparam->def.datatype == OGCONN_TYPE_CURSOR) {
PRTS_RETURN_IFERR(snprintf_s(str, buf_size, buf_size - 1, "CURSOR STATEMENT"));
}
return OG_SUCCESS;
}
return ogconn_outparam_as_string_get_data(stmt, id, str, buf_size, outparam, size, data);
}
status_t ogconn_outparam_as_string_by_id(ogconn_stmt_t pstmt, uint32 id, char *str, uint32 buf_size)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_outparam_as_string_by_id(stmt, id, str, buf_size);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_outparam_as_string_by_name(clt_stmt_t *stmt, const char *name, char *str, uint32 buf_size)
{
clt_outparam_t *outparam = NULL;
uint32 i;
for (i = 0; i < stmt->outparam_count && i < stmt->outparams.count; i++) {
outparam = (clt_outparam_t *)cm_list_get(&stmt->outparams, i);
if (cm_str_equal_ins(name, outparam->def.name)) {
return clt_outparam_as_string_by_id(stmt, i, str, buf_size);
}
}
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_ATTR, "outparam name", name);
return OG_ERROR;
}
status_t ogconn_outparam_as_string_by_name(ogconn_stmt_t pstmt, const char *name, char *str, uint32 buf_size)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, name, "name");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_outparam_as_string_by_name(stmt, name, str, buf_size);
clt_unlock_conn(stmt->conn);
return status;
}
#define MAX_DESC_SQL 1024
static status_t clt_desc_tbl_vw_syn(clt_stmt_t *stmt, const char *obj_name)
{
char desc_sql[MAX_SET_NLS_SQL];
text_t sql_text;
if (strlen(obj_name) > OG_MAX_NAME_LEN * 2) {
CLT_SET_ERROR(stmt->conn, ERR_INVALID_PARAMETER, "the object name is too long");
return OG_ERROR;
}
PRTS_RETURN_IFERR(sprintf_s(desc_sql, MAX_SET_NLS_SQL, "select * from %s", obj_name));
sql_text.str = desc_sql;
sql_text.len = (uint32)strlen(desc_sql);
OG_RETURN_IFERR(clt_prepare(stmt, &sql_text));
stmt->status = CLI_STMT_DESCRIBLE;
return OG_SUCCESS;
}
static status_t clt_desc_query(clt_stmt_t *stmt, char *query)
{
static const text_t word_select = {
.str = "SELECT",
.len = 6
};
static const text_t word_with = {
.str = "WITH",
.len = 4
};
text_t sql_text;
sql_text.str = query;
sql_text.len = (uint32)strlen(query);
cm_trim_text(&sql_text);
if ((cm_strcmpni(sql_text.str, word_select.str, word_select.len) != 0) &&
(cm_strcmpni(sql_text.str, word_with.str, word_with.len) != 0)) {
CLT_SET_ERROR(stmt->conn, ERR_INVALID_PARAMETER, "a query is expected");
return OG_ERROR;
}
OG_RETURN_IFERR(clt_prepare(stmt, &sql_text));
stmt->status = CLI_STMT_DESCRIBLE;
return OG_SUCCESS;
}
static status_t clt_describle(clt_stmt_t *stmt, char *objptr, ogconn_desc_type_t desc_type)
{
ogconn_desc_type_t dtype = desc_type;
if (dtype == OGCONN_DESC_OBJ) {
dtype = OGCONN_DESC_TABLE;
}
switch (dtype) {
case OGCONN_DESC_TABLE:
case OGCONN_DESC_VIEW:
case OGCONN_DESC_SYN:
return clt_desc_tbl_vw_syn(stmt, objptr);
case OGCONN_DESC_QUERY:
return clt_desc_query(stmt, objptr);
case OGCONN_DESC_PROC:
CLT_SET_ERROR(stmt->conn, ERR_INVALID_PARAMETER, "describle procedure is unsupported");
return OG_ERROR;
case OGCONN_DESC_FUNC:
CLT_SET_ERROR(stmt->conn, ERR_INVALID_PARAMETER, "describle function is unsupported");
return OG_ERROR;
case OGCONN_DESC_PKG:
CLT_SET_ERROR(stmt->conn, ERR_INVALID_PARAMETER, "describle package is unsupported");
return OG_ERROR;
case OGCONN_DESC_SEQ:
CLT_SET_ERROR(stmt->conn, ERR_INVALID_PARAMETER, "describle sequence is unsupported");
return OG_ERROR;
default:
CLT_SET_ERROR(stmt->conn, ERR_INVALID_PARAMETER, "unsupported describing type");
return OG_ERROR;
}
}
status_t ogconn_describle(ogconn_stmt_t pstmt, char *objptr, ogconn_desc_type_t dtype)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, objptr, "describle object");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
if (clt_prepare_stmt_pack(stmt) != OG_SUCCESS) {
clt_unlock_conn(stmt->conn);
return OG_ERROR;
}
status = clt_describle(stmt, objptr, dtype);
clt_recycle_stmt_pack(stmt);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_get_batch_error2(clt_stmt_t *stmt, uint32 *line, int *code, char **err_message, uint32 *rows)
{
clt_batch_error_t *batch_error = NULL;
if (SECUREC_UNLIKELY(line == NULL || err_message == NULL || rows == NULL)) {
OG_THROW_ERROR(ERR_CLT_OBJECT_IS_NULL, "line or err_message or rows");
return OG_ERROR;
}
if (stmt->batch_errs.pos >= stmt->batch_errs.actual_count) {
*rows = 0;
} else {
batch_error = (clt_batch_error_t *)cm_list_get(&stmt->batch_errs.err_list, stmt->batch_errs.pos);
*line = batch_error->line;
if (code != NULL) {
*code = batch_error->err_code;
}
*err_message = batch_error->err_message;
*rows = 1;
stmt->batch_errs.pos++;
}
return OG_SUCCESS;
}
status_t ogconn_get_batch_error(ogconn_stmt_t pstmt, uint32 *line, char **err_message, uint32 *rows)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_get_batch_error2(stmt, line, NULL, err_message, rows);
clt_unlock_conn(stmt->conn);
return status;
}
status_t ogconn_get_batch_error2(ogconn_stmt_t pstmt, unsigned int *line, int *code, char **err_message, unsigned int
*rows)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_get_batch_error2(stmt, line, code, err_message, rows);
clt_unlock_conn(stmt->conn);
return status;
}
static status_t clt_get_query_resultset(clt_conn_t *conn, clt_stmt_t **resultset)
{
clt_query_t *query = &conn->query;
uint32 stmt_id;
if (query->pos >= query->ids.count) {
*resultset = NULL;
} else {
stmt_id = *(uint32 *)cm_list_get(&query->ids, query->pos);
*resultset = (clt_stmt_t *)cm_ptlist_get(&conn->stmts, stmt_id);
query->pos++;
}
return OG_SUCCESS;
}
status_t ogconn_get_query_resultset(ogconn_conn_t pconn, ogconn_stmt_t *resultset)
{
status_t status;
clt_conn_t *conn = (clt_conn_t *)pconn;
OGCONN_CHECK_OBJECT_NULL_GS(conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(conn, resultset, "resultset");
OG_RETURN_IFERR(clt_lock_conn(conn));
status = clt_get_query_resultset(conn, (clt_stmt_t **)resultset);
clt_unlock_conn(conn);
return status;
}
static int clt_read_ori_row(clt_stmt_t *stmt, void **ori_row, unsigned int *size)
{
if (stmt->status < CLI_STMT_FETCHING) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_OUT_OF_API_SEQUENCE, "statement is not fetched");
return OG_ERROR;
}
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, stmt->ori_row, "ori row");
if (ori_row != NULL) {
*ori_row = stmt->ori_row;
}
if (size != NULL) {
*size = *(uint16 *)stmt->ori_row;
}
return OG_SUCCESS;
}
int ogconn_read_ori_row(ogconn_stmt_t pstmt, void **ori_row, unsigned int *size)
{
status_t status;
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OG_RETURN_IFERR(clt_lock_conn(stmt->conn));
status = clt_read_ori_row(stmt, ori_row, size);
clt_unlock_conn(stmt->conn);
return status;
}
status_t ogconn_number_to_int(ogconn_stmt_t pstmt, void *number, unsigned int sign_flag, unsigned int rsl_length, void
*rsl)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
dec4_t *dec = (dec4_t *)number;
int16 val16;
int32 val32;
int64 val64;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, number, "number");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, rsl, "rsl");
if (sign_flag != OGCONN_NUMBER_SIGNED && sign_flag != OGCONN_NUMBER_UNSIGNED) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "sign_flag", sign_flag);
return OG_ERROR;
}
switch (rsl_length) {
case sizeof(int16):
if (sign_flag == OGCONN_NUMBER_SIGNED) {
CLT_SET_LOCAL_ERROR(stmt->conn, cm_dec4_to_int16(dec, &val16, ROUND_HALF_UP));
} else {
CLT_SET_LOCAL_ERROR(stmt->conn, cm_dec4_to_uint16(dec, (uint16 *)&val16, ROUND_HALF_UP));
}
*(int16 *)rsl = val16;
break;
case sizeof(int32):
if (sign_flag == OGCONN_NUMBER_SIGNED) {
CLT_SET_LOCAL_ERROR(stmt->conn, cm_dec4_to_int32(dec, &val32, ROUND_HALF_UP));
} else {
CLT_SET_LOCAL_ERROR(stmt->conn, cm_dec4_to_uint32(dec, (uint32 *)&val32, ROUND_HALF_UP));
}
*(int32 *)rsl = val32;
break;
case sizeof(int64):
if (sign_flag == OGCONN_NUMBER_SIGNED) {
CLT_SET_LOCAL_ERROR(stmt->conn, cm_dec4_to_int64(dec, &val64, ROUND_HALF_UP));
} else if (sign_flag == OGCONN_NUMBER_UNSIGNED) {
CLT_SET_LOCAL_ERROR(stmt->conn, cm_dec4_to_uint64(dec, (uint64 *)&val64, ROUND_HALF_UP));
}
*(int64 *)rsl = val64;
break;
default:
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "result length", rsl_length);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t ogconn_number_to_real(ogconn_stmt_t pstmt, void *number, unsigned int rsl_length, void *rsl)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
dec4_t *dec = (dec4_t *)number;
double val;
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, number, "number");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, rsl, "rsl");
val = cm_dec4_to_real(dec);
switch (rsl_length) {
case sizeof(float):
if (val != 0 && ((dec->sign == 0 && (val > FLT_MAX || val < FLT_MIN)) ||
(dec->sign == 1 && (val < -FLT_MAX || val > -FLT_MIN)))) {
CLT_THROW_ERROR(stmt->conn, ERR_TYPE_OVERFLOW, "FLOAT");
return OG_ERROR;
}
*(float *)rsl = (float)val;
break;
case sizeof(double):
*(double *)rsl = val;
break;
default:
CLT_THROW_ERROR(stmt->conn, ERR_CLT_INVALID_VALUE, "result length", rsl_length);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t ogconn_number_to_string(ogconn_stmt_t pstmt, void *number, char *buf, unsigned int buf_size)
{
clt_stmt_t *stmt = (clt_stmt_t *)pstmt;
dec4_t *dec = (dec4_t *)number;
int max_size = MIN(buf_size, OG_NUMBER_BUFFER_SIZE);
OGCONN_CHECK_OBJECT_NULL_GS(stmt, "statement");
OGCONN_CHECK_OBJECT_NULL_GS(stmt->conn, "connection");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, number, "number");
OGCONN_CHECK_OBJECT_NULL_CLT(stmt->conn, buf, "buf");
if (cm_dec4_to_str(dec, max_size, buf) != OG_SUCCESS) {
CLT_THROW_ERROR(stmt->conn, ERR_CLT_BUF_SIZE_TOO_SMALL, "convert to string");
return OG_ERROR;
}
return OG_SUCCESS;
}
#ifdef WIN32
const char *ogconn_get_dbversion()
{
return "NONE";
}
#else
extern const char *ogconn_get_dbversion(void);
#endif
const char *ogconn_get_version(void)
{
return ogconn_get_dbversion();
}
char *ogconn_get_typename_by_id(ogconn_type_t ogconn_type)
{
struct st_ctconn_datatype {
ogconn_type_t typid;
char *typname;
} type_map[] = {
{ OGCONN_TYPE_UNKNOWN, (char *)"UNKNOWN_TYPE", },
{ OGCONN_TYPE_INTEGER, (char *)"BINARY_INTEGER", },
{ OGCONN_TYPE_BIGINT, (char *)"BINARY_BIGINT", },
{ OGCONN_TYPE_REAL, (char *)"BINARY_DOUBLE", },
{ OGCONN_TYPE_NUMBER, (char *)"NUMBER", },
{ OGCONN_TYPE_NUMBER2, (char *)"NUMBER2", },
{ OGCONN_TYPE_DECIMAL, (char *)"DECIMAL", },
{ OGCONN_TYPE_DATE, (char *)"DATE", },
{ OGCONN_TYPE_TIMESTAMP, (char *)"TIMESTAMP", },
{ OGCONN_TYPE_CHAR, (char *)"CHAR", },
{ OGCONN_TYPE_VARCHAR, (char *)"VARCHAR", },
{ OGCONN_TYPE_STRING, (char *)"VARCHAR", },
{ OGCONN_TYPE_BINARY, (char *)"BINARY", },
{ OGCONN_TYPE_VARBINARY, (char *)"VARBINARY", },
{ OGCONN_TYPE_CLOB, (char *)"CLOB", },
{ OGCONN_TYPE_BLOB, (char *)"BLOB", },
{ OGCONN_TYPE_CURSOR, (char *)"CURSOR", },
{ OGCONN_TYPE_COLUMN, (char *)"COLUMN", },
{ OGCONN_TYPE_BOOLEAN, (char *)"BOOLEAN", },
{ OGCONN_TYPE_TIMESTAMP_TZ_FAKE, (char *)"TIMESTAMP", },
{ OGCONN_TYPE_TIMESTAMP_LTZ, (char *)"TIMESTAMP_LTZ", },
{ OGCONN_TYPE_INTERVAL, (char *)"INTERVAL", },
{ OGCONN_TYPE_INTERVAL_YM, (char *)"INTERVAL YEAR TO MONTH", },
{ OGCONN_TYPE_INTERVAL_DS, (char *)"INTERVAL DAY TO SECOND", },
{ OGCONN_TYPE_RAW, (char *)"RAW", },
{ OGCONN_TYPE_IMAGE, (char *)"IMAGE", },
{ OGCONN_TYPE_UINT32, (char *)"BINARY_UINT32" },
{ OGCONN_TYPE_TIMESTAMP_TZ, (char *)"TIMESTAMP_TZ", },
{ OGCONN_TYPE_ARRAY, (char *)"ARRAY", },
{ OGCONN_TYPE_NATIVE_DATE, (char *)"NATIVE_DATE", }
};
uint32 type_cnt = sizeof(type_map) / sizeof(type_map[0]);
uint32 i;
for (i = 0; i < type_cnt; i++) {
if (type_map[i].typid == ogconn_type) {
return type_map[i].typname;
}
}
return type_map[0].typname;
}
#ifdef __cplusplus
}
#endif