/** * Convert parameters to libtds format * @return SQL_SUCCESS, SQL_ERROR or SQL_NEED_DATA */ SQLRETURN sql2tds(TDS_DBC * dbc, struct _drecord *drec_ipd, struct _drecord *drec_apd, TDSPARAMINFO * info, int nparam) { int dest_type, src_type, res; CONV_RESULT ores; TDSBLOBINFO *blob_info; char *src; unsigned char *dest; TDSCOLINFO *curcol = info->columns[nparam]; int len; TDS_DATETIME dt; TDS_NUMERIC num; SQL_NUMERIC_STRUCT *sql_num; SQLINTEGER sql_len; int need_data = 0, i; /* TODO handle bindings of char like "{d '2002-11-12'}" */ tdsdump_log(TDS_DBG_INFO2, "%s:%d type=%d\n", __FILE__, __LINE__, drec_ipd->sql_desc_concise_type); /* what type to convert ? */ dest_type = odbc_sql_to_server_type(dbc->tds_socket, drec_ipd->sql_desc_concise_type); if (dest_type == TDS_FAIL) return SQL_ERROR; tdsdump_log(TDS_DBG_INFO2, "%s:%d\n", __FILE__, __LINE__); /* TODO what happen for unicode types ?? */ tds_set_param_type(dbc->tds_socket, curcol, dest_type); if (is_numeric_type(curcol->column_type)) { curcol->column_prec = drec_ipd->sql_desc_precision; curcol->column_scale = drec_ipd->sql_desc_scale; } if (drec_ipd->sql_desc_parameter_type != SQL_PARAM_INPUT) curcol->column_output = 1; /* compute destination length */ if (curcol->column_varint_size != 0) { /* curcol->column_size = drec_apd->sql_desc_octet_length; */ /* * TODO destination length should come from sql_desc_length, * however there is the encoding problem to take into account * we should fill destination length after conversion keeping * attention to fill correctly blob/fixed type/variable type */ curcol->column_cur_size = 0; curcol->column_size = drec_ipd->sql_desc_length; if (curcol->column_size < 0) curcol->column_size = 0x7FFFFFFFl; } else { /* TODO only a trick... */ if (curcol->column_varint_size == 0) tds_set_param_type(dbc->tds_socket, curcol, tds_get_null_type(dest_type)); } /* get C type */ src_type = drec_apd->sql_desc_concise_type; if (src_type == SQL_C_DEFAULT) src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type); /* if only output assume input is NULL */ if (drec_ipd->sql_desc_parameter_type == SQL_PARAM_OUTPUT) sql_len = SQL_NULL_DATA; else sql_len = odbc_get_param_len(dbc->tds_socket, drec_apd, drec_ipd); /* compute source length */ switch (sql_len) { case SQL_NULL_DATA: len = 0; break; case SQL_NTS: len = strlen(drec_apd->sql_desc_data_ptr); break; case SQL_DEFAULT_PARAM: case SQL_DATA_AT_EXEC: /* TODO */ return SQL_ERROR; break; default: len = sql_len; if (sql_len < 0) { /* test for SQL_C_CHAR/SQL_C_BINARY */ switch (src_type) { case SQL_C_CHAR: case SQL_C_BINARY: break; default: return SQL_ERROR; } len = SQL_LEN_DATA_AT_EXEC(sql_len); need_data = 1; /* other trick, set length of destination */ switch (odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type)) { case SQL_C_CHAR: case SQL_C_BINARY: curcol->column_size = len; break; } } } /* allocate given space */ if (!tds_alloc_param_row(info, curcol)) return SQL_ERROR; /* test source type */ /* TODO test intervals */ src_type = odbc_c_to_server_type(src_type); if (src_type == TDS_FAIL) return SQL_ERROR; if (need_data) { curcol->column_cur_size = 0; return SQL_NEED_DATA; } /* set null */ assert(drec_ipd->sql_desc_parameter_type != SQL_PARAM_OUTPUT || sql_len == SQL_NULL_DATA); if (sql_len == SQL_NULL_DATA) { curcol->column_cur_size = 0; tds_set_null(info->current_row, nparam); return TDS_SUCCEED; } /* convert special parameters (not libTDS compatible) */ src = drec_apd->sql_desc_data_ptr; switch (src_type) { case SYBDATETIME: convert_datetime2server(drec_apd->sql_desc_concise_type, src, &dt); src = (char *) &dt; break; case SYBDECIMAL: case SYBNUMERIC: sql_num = (SQL_NUMERIC_STRUCT *) src; num.precision = sql_num->precision; num.scale = sql_num->scale; num.array[0] = sql_num->sign ^ 1; /* TODO test precision so client do not crash our library ?? */ i = tds_numeric_bytes_per_prec[num.precision]; memcpy(num.array + 1, sql_num->val, i); tds_swap_bytes(num.array + 1, i); ++i; if (i < sizeof(num.array)) memset(num.array + i, 0, sizeof(num.array) - i); src = (char *) # /* set output */ /* TODO use descriptors informations ?? */ ores.n.precision = 18; ores.n.scale = 2; break; /* TODO intervals */ } res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, &ores); if (res < 0) return SQL_ERROR; tdsdump_log(TDS_DBG_INFO2, "%s:%d\n", __FILE__, __LINE__); /* truncate ?? */ /* TODO what happen for blobs ?? */ if (res > curcol->column_size) res = curcol->column_size; curcol->column_cur_size = res; /* free allocated memory */ dest = &info->current_row[curcol->column_offset]; switch ((TDS_SERVER_TYPE) dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: memcpy(&info->current_row[curcol->column_offset], ores.c, res); free(ores.c); break; case SYBTEXT: blob_info = (TDSBLOBINFO *) dest; if (blob_info->textvalue) free(blob_info->textvalue); blob_info->textvalue = ores.c; break; case SYBBINARY: case SYBVARBINARY: case XSYBBINARY: case XSYBVARBINARY: memcpy(&info->current_row[curcol->column_offset], ores.ib, res); free(ores.ib); break; case SYBLONGBINARY: case SYBIMAGE: blob_info = (TDSBLOBINFO *) dest; if (blob_info->textvalue) free(blob_info->textvalue); blob_info->textvalue = ores.ib; break; case SYBINTN: case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBDATETIME: case SYBBIT: case SYBMONEY4: case SYBMONEY: case SYBDATETIME4: case SYBREAL: case SYBBITN: case SYBNUMERIC: case SYBDECIMAL: case SYBFLTN: case SYBMONEYN: case SYBDATETIMN: case SYBSINT1: case SYBUINT2: case SYBUINT4: case SYBUINT8: case SYBUNIQUE: memcpy(&info->current_row[curcol->column_offset], &ores, res); break; case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: case SYBNTEXT: case SYBVOID: case SYBVARIANT: /* TODO ODBC 3.5 */ assert(0); break; } return SQL_SUCCESS; }
/** * Convert parameters to libtds format * @return SQL_SUCCESS, SQL_ERROR or SQL_NEED_DATA */ SQLRETURN odbc_sql2tds(TDS_STMT * stmt, const struct _drecord *drec_ipd, const struct _drecord *drec_apd, TDSCOLUMN *curcol, int compute_row, const TDS_DESC* axd, unsigned int n_row) { TDS_DBC * dbc = stmt->dbc; TDSCONNECTION * conn = dbc->tds_socket->conn; int dest_type, src_type, sql_src_type, res; CONV_RESULT ores; TDSBLOB *blob; char *src, *converted_src; unsigned char *dest; int len; TDS_DATETIMEALL dta; TDS_NUMERIC num; SQL_NUMERIC_STRUCT *sql_num; SQLINTEGER sql_len; int need_data = 0, i; /* TODO handle bindings of char like "{d '2002-11-12'}" */ tdsdump_log(TDS_DBG_INFO2, "type=%d\n", drec_ipd->sql_desc_concise_type); /* what type to convert ? */ dest_type = odbc_sql_to_server_type(conn, drec_ipd->sql_desc_concise_type, drec_ipd->sql_desc_unsigned); if (!dest_type) { odbc_errs_add(&stmt->errs, "07006", NULL); /* Restricted data type attribute violation */ return SQL_ERROR; } tdsdump_log(TDS_DBG_INFO2, "trace\n"); /* get C type */ sql_src_type = drec_apd->sql_desc_concise_type; if (sql_src_type == SQL_C_DEFAULT) sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type); /* TODO what happen for unicode types ?? */ if (is_char_type(dest_type) && sql_src_type == SQL_C_WCHAR) { TDSICONV *conv = conn->char_convs[is_unicode_type(dest_type) ? client2ucs2 : client2server_chardata]; tds_set_param_type(conn, curcol, dest_type); curcol->char_conv = tds_iconv_get(conn, odbc_get_wide_name(conn), conv->to.charset.name); memcpy(curcol->column_collation, conn->collation, sizeof(conn->collation)); } else { #ifdef ENABLE_ODBC_WIDE TDSICONV *conv = conn->char_convs[is_unicode_type(dest_type) ? client2ucs2 : client2server_chardata]; tds_set_param_type(conn, curcol, dest_type); /* use binary format for binary to char */ if (is_char_type(dest_type)) curcol->char_conv = sql_src_type == SQL_C_BINARY ? NULL : tds_iconv_get(conn, tds_dstr_cstr(&dbc->original_charset), conv->to.charset.name); #else tds_set_param_type(conn, curcol, dest_type); /* use binary format for binary to char */ if (sql_src_type == SQL_C_BINARY && is_char_type(dest_type)) curcol->char_conv = NULL; #endif } if (is_numeric_type(curcol->column_type)) { curcol->column_prec = drec_ipd->sql_desc_precision; curcol->column_scale = drec_ipd->sql_desc_scale; } if (drec_ipd->sql_desc_parameter_type != SQL_PARAM_INPUT) curcol->column_output = 1; /* compute destination length */ if (curcol->column_varint_size != 0) { /* curcol->column_size = drec_apd->sql_desc_octet_length; */ /* * TODO destination length should come from sql_desc_length, * however there is the encoding problem to take into account * we should fill destination length after conversion keeping * attention to fill correctly blob/fixed type/variable type */ /* TODO location of this test is correct here ?? */ if (dest_type != SYBUNIQUE && dest_type != SYBBITN && !is_fixed_type(dest_type)) { curcol->column_cur_size = 0; curcol->column_size = drec_ipd->sql_desc_length; if (curcol->column_size < 0) { curcol->on_server.column_size = curcol->column_size = 0x7FFFFFFFl; } else { if (is_unicode_type(dest_type)) curcol->on_server.column_size = curcol->column_size * 2; else curcol->on_server.column_size = curcol->column_size; } } } else if (dest_type != SYBBIT) { /* TODO only a trick... */ tds_set_param_type(conn, curcol, tds_get_null_type(dest_type)); } /* test source type */ /* TODO test intervals */ src_type = odbc_c_to_server_type(sql_src_type); if (!src_type) { odbc_errs_add(&stmt->errs, "07006", NULL); /* Restricted data type attribute violation */ return SQL_ERROR; } /* we have no data to convert, just return */ if (!compute_row) return SQL_SUCCESS; src = drec_apd->sql_desc_data_ptr; if (src && n_row) { SQLLEN len; if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) { len = axd->header.sql_desc_bind_type; if (axd->header.sql_desc_bind_offset_ptr) src += *axd->header.sql_desc_bind_offset_ptr; } else { len = odbc_get_octet_len(sql_src_type, drec_apd); if (len < 0) /* TODO sure ? what happen to upper layer ?? */ /* TODO fill error */ return SQL_ERROR; } src += len * n_row; } /* if only output assume input is NULL */ if (drec_ipd->sql_desc_parameter_type == SQL_PARAM_OUTPUT) { sql_len = SQL_NULL_DATA; } else { sql_len = odbc_get_param_len(drec_apd, drec_ipd, axd, n_row); /* special case, MS ODBC handle conversion from "\0" to any to NULL, DBD::ODBC require it */ if (src_type == SYBVARCHAR && sql_len == 1 && drec_ipd->sql_desc_parameter_type == SQL_PARAM_INPUT_OUTPUT && src && *src == 0) { sql_len = SQL_NULL_DATA; } } /* compute source length */ switch (sql_len) { case SQL_NULL_DATA: len = 0; break; case SQL_NTS: /* check that SQLBindParameter::ParameterValuePtr is not zero for input parameters */ if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } if (sql_src_type == SQL_C_WCHAR) len = sqlwcslen((const SQLWCHAR *) src) * sizeof(SQLWCHAR); else len = strlen(src); break; case SQL_DEFAULT_PARAM: odbc_errs_add(&stmt->errs, "07S01", NULL); /* Invalid use of default parameter */ return SQL_ERROR; break; case SQL_DATA_AT_EXEC: default: len = sql_len; if (sql_len < 0) { /* test for SQL_C_CHAR/SQL_C_BINARY */ switch (sql_src_type) { case SQL_C_CHAR: case SQL_C_WCHAR: case SQL_C_BINARY: break; default: odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } len = SQL_LEN_DATA_AT_EXEC(sql_len); need_data = 1; /* dynamic length allowed only for BLOB fields */ switch (drec_ipd->sql_desc_concise_type) { case SQL_LONGVARCHAR: case SQL_WLONGVARCHAR: case SQL_LONGVARBINARY: break; default: odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } } } /* set NULL. For NULLs we don't need to allocate row buffer so avoid it */ if (!need_data) { assert(drec_ipd->sql_desc_parameter_type != SQL_PARAM_OUTPUT || sql_len == SQL_NULL_DATA); if (sql_len == SQL_NULL_DATA) { curcol->column_cur_size = -1; return SQL_SUCCESS; } } switch (dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: case SYBNTEXT: case SYBTEXT: if (!need_data && (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR || sql_src_type == SQL_C_BINARY)) { if (curcol->column_data && curcol->column_data_free) curcol->column_data_free(curcol); curcol->column_data_free = NULL; if (is_blob_col(curcol)) { /* trick to set blob without freeing it, _odbc_blob_free does not free TDSBLOB->textvalue */ TDSBLOB *blob = (TDSBLOB *) calloc(1, sizeof(TDSBLOB)); if (!blob) { odbc_errs_add(&stmt->errs, "HY001", NULL); return SQL_ERROR; } blob->textvalue = src; curcol->column_data = (TDS_UCHAR*) blob; curcol->column_data_free = _odbc_blob_free; } else { curcol->column_data = (TDS_UCHAR*) src; } curcol->column_size = len; curcol->column_cur_size = len; return SQL_SUCCESS; } } /* allocate given space */ if (!tds_alloc_param_data(curcol)) { odbc_errs_add(&stmt->errs, "HY001", NULL); return SQL_ERROR; } /* fill data with SQLPutData */ if (need_data) { curcol->column_cur_size = 0; return SQL_NEED_DATA; } if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } /* convert special parameters (not libTDS compatible) */ switch (src_type) { case SYBMSDATETIME2: convert_datetime2server(drec_apd->sql_desc_concise_type, src, &dta); src = (char *) &dta; break; case SYBDECIMAL: case SYBNUMERIC: sql_num = (SQL_NUMERIC_STRUCT *) src; num.precision = sql_num->precision; num.scale = sql_num->scale; num.array[0] = sql_num->sign ^ 1; /* test precision so client do not crash our library */ if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision) /* TODO add proper error */ return SQL_ERROR; i = tds_numeric_bytes_per_prec[num.precision]; memcpy(num.array + 1, sql_num->val, i - 1); tds_swap_bytes(num.array + 1, i - 1); if (i < sizeof(num.array)) memset(num.array + i, 0, sizeof(num.array) - i); src = (char *) # break; /* TODO intervals */ } converted_src = NULL; if (sql_src_type == SQL_C_WCHAR) { converted_src = src = odbc_wstr2str(stmt, src, &len); if (!src) return SQL_ERROR; src_type = SYBVARCHAR; } dest = curcol->column_data; switch ((TDS_SERVER_TYPE) dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: ores.cc.c = (TDS_CHAR*) dest; ores.cc.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_CHAR, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBBINARY: case SYBVARBINARY: case XSYBBINARY: case XSYBVARBINARY: ores.cb.ib = (TDS_CHAR*) dest; ores.cb.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_BINARY, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBNTEXT: dest_type = SYBTEXT; case SYBTEXT: case SYBLONGBINARY: case SYBIMAGE: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, &ores); if (res >= 0) { blob = (TDSBLOB *) dest; free(blob->textvalue); blob->textvalue = ores.ib; } break; case SYBNUMERIC: case SYBDECIMAL: ((TDS_NUMERIC *) dest)->precision = drec_ipd->sql_desc_precision; ((TDS_NUMERIC *) dest)->scale = drec_ipd->sql_desc_scale; case SYBINTN: case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBDATETIME: case SYBBIT: case SYBMONEY4: case SYBMONEY: case SYBDATETIME4: case SYBREAL: case SYBBITN: case SYBFLTN: case SYBMONEYN: case SYBDATETIMN: case SYBSINT1: case SYBUINT2: case SYBUINT4: case SYBUINT8: case SYBUNIQUE: case SYBMSTIME: case SYBMSDATE: case SYBMSDATETIME2: case SYBMSDATETIMEOFFSET: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, (CONV_RESULT*) dest); break; default: case SYBVOID: case SYBVARIANT: /* TODO ODBC 3.5 */ assert(0); res = -1; break; } free(converted_src); if (res < 0) { odbc_convert_err_set(&stmt->errs, res); return SQL_ERROR; } curcol->column_cur_size = res; return SQL_SUCCESS; }
/** * Convert parameters to libtds format * @return SQL_SUCCESS, SQL_ERROR or SQL_NEED_DATA */ SQLRETURN sql2tds(TDS_STMT * stmt, const struct _drecord *drec_ipd, const struct _drecord *drec_apd, TDSCOLUMN *curcol, int compute_row, const TDS_DESC* axd, unsigned int n_row) { TDS_DBC * dbc = stmt->dbc; int dest_type, src_type, sql_src_type, res; CONV_RESULT ores; TDSBLOB *blob; char *src; unsigned char *dest; int len; TDS_DATETIME dt; TDS_NUMERIC num; SQL_NUMERIC_STRUCT *sql_num; SQLINTEGER sql_len; int need_data = 0, i; /* TODO handle bindings of char like "{d '2002-11-12'}" */ tdsdump_log(TDS_DBG_INFO2, "type=%d\n", drec_ipd->sql_desc_concise_type); /* what type to convert ? */ dest_type = odbc_sql_to_server_type(dbc->tds_socket, drec_ipd->sql_desc_concise_type); if (dest_type == TDS_FAIL) return SQL_ERROR; tdsdump_log(TDS_DBG_INFO2, "trace\n"); /* TODO what happen for unicode types ?? */ tds_set_param_type(dbc->tds_socket, curcol, dest_type); if (is_numeric_type(curcol->column_type)) { curcol->column_prec = drec_ipd->sql_desc_precision; curcol->column_scale = drec_ipd->sql_desc_scale; } if (drec_ipd->sql_desc_parameter_type != SQL_PARAM_INPUT) curcol->column_output = 1; /* compute destination length */ if (curcol->column_varint_size != 0) { /* curcol->column_size = drec_apd->sql_desc_octet_length; */ /* * TODO destination length should come from sql_desc_length, * however there is the encoding problem to take into account * we should fill destination length after conversion keeping * attention to fill correctly blob/fixed type/variable type */ /* TODO location of this test is correct here ?? */ if (dest_type != SYBUNIQUE && dest_type != SYBBITN && !is_fixed_type(dest_type)) { curcol->column_cur_size = 0; curcol->column_size = drec_ipd->sql_desc_length; if (curcol->column_size < 0) curcol->column_size = 0x7FFFFFFFl; } } else if (dest_type != SYBBIT) { /* TODO only a trick... */ tds_set_param_type(dbc->tds_socket, curcol, tds_get_null_type(dest_type)); } /* get C type */ sql_src_type = drec_apd->sql_desc_concise_type; if (sql_src_type == SQL_C_DEFAULT) sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type); /* test source type */ /* TODO test intervals */ src_type = odbc_c_to_server_type(sql_src_type); if (src_type == TDS_FAIL) return SQL_ERROR; /* we have no data to convert, just return */ if (!compute_row) return TDS_SUCCEED; src = drec_apd->sql_desc_data_ptr; if (src && n_row) { SQLLEN len; if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) { len = axd->header.sql_desc_bind_type; if (axd->header.sql_desc_bind_offset_ptr) src += *axd->header.sql_desc_bind_offset_ptr; } else { len = odbc_get_octet_len(sql_src_type, drec_apd); if (len < 0) /* TODO sure ? what happen to upper layer ?? */ return SQL_ERROR; } src += len * n_row; } /* if only output assume input is NULL */ if (drec_ipd->sql_desc_parameter_type == SQL_PARAM_OUTPUT) { sql_len = SQL_NULL_DATA; } else { sql_len = odbc_get_param_len(drec_apd, drec_ipd, axd, n_row); /* special case, MS ODBC handle conversion from "\0" to any to NULL, DBD::ODBC require it */ if (src_type == SYBVARCHAR && sql_len == 1 && drec_ipd->sql_desc_parameter_type == SQL_PARAM_INPUT_OUTPUT && src && *src == 0) { sql_len = SQL_NULL_DATA; } } /* compute source length */ switch (sql_len) { case SQL_NULL_DATA: len = 0; break; case SQL_NTS: /* check that SQLBindParameter::ParameterValuePtr is not zero for input parameters */ if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } len = strlen(src); break; case SQL_DEFAULT_PARAM: case SQL_DATA_AT_EXEC: /* TODO */ return SQL_ERROR; break; default: len = sql_len; if (sql_len < 0) { /* test for SQL_C_CHAR/SQL_C_BINARY */ switch (sql_src_type) { case SQL_C_CHAR: case SQL_C_BINARY: break; default: return SQL_ERROR; } len = SQL_LEN_DATA_AT_EXEC(sql_len); need_data = 1; /* dynamic length allowed only for BLOB fields */ switch (drec_ipd->sql_desc_concise_type) { case SQL_LONGVARCHAR: case SQL_LONGVARBINARY: break; default: return SQL_ERROR; } } } /* allocate given space */ if (!tds_alloc_param_data(curcol)) return SQL_ERROR; if (need_data) { curcol->column_cur_size = 0; return SQL_NEED_DATA; } /* set null */ assert(drec_ipd->sql_desc_parameter_type != SQL_PARAM_OUTPUT || sql_len == SQL_NULL_DATA); if (sql_len == SQL_NULL_DATA) { curcol->column_cur_size = -1; return TDS_SUCCEED; } if (!src) { odbc_errs_add(&stmt->errs, "HY090", NULL); return SQL_ERROR; } /* convert special parameters (not libTDS compatible) */ switch (src_type) { case SYBDATETIME: convert_datetime2server(drec_apd->sql_desc_concise_type, src, &dt); src = (char *) &dt; break; case SYBDECIMAL: case SYBNUMERIC: sql_num = (SQL_NUMERIC_STRUCT *) src; num.precision = sql_num->precision; num.scale = sql_num->scale; num.array[0] = sql_num->sign ^ 1; /* test precision so client do not crash our library */ if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision) /* TODO add proper error */ return SQL_ERROR; i = tds_numeric_bytes_per_prec[num.precision]; memcpy(num.array + 1, sql_num->val, i - 1); tds_swap_bytes(num.array + 1, i - 1); if (i < sizeof(num.array)) memset(num.array + i, 0, sizeof(num.array) - i); src = (char *) # break; /* TODO intervals */ } dest = curcol->column_data; switch ((TDS_SERVER_TYPE) dest_type) { case SYBCHAR: case SYBVARCHAR: case XSYBCHAR: case XSYBVARCHAR: ores.cc.c = (TDS_CHAR*) dest; ores.cc.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_CHAR, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBBINARY: case SYBVARBINARY: case XSYBBINARY: case XSYBVARBINARY: ores.cb.ib = (TDS_CHAR*) dest; ores.cb.len = curcol->column_size; res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_BINARY, &ores); if (res > curcol->column_size) res = curcol->column_size; break; case SYBTEXT: case SYBLONGBINARY: case SYBIMAGE: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, &ores); if (res < 0) return SQL_ERROR; blob = (TDSBLOB *) dest; free(blob->textvalue); blob->textvalue = ores.ib; break; case SYBNUMERIC: case SYBDECIMAL: ((TDS_NUMERIC *) dest)->precision = drec_ipd->sql_desc_precision; ((TDS_NUMERIC *) dest)->scale = drec_ipd->sql_desc_scale; case SYBINTN: case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBDATETIME: case SYBBIT: case SYBMONEY4: case SYBMONEY: case SYBDATETIME4: case SYBREAL: case SYBBITN: case SYBFLTN: case SYBMONEYN: case SYBDATETIMN: case SYBSINT1: case SYBUINT2: case SYBUINT4: case SYBUINT8: case SYBUNIQUE: res = tds_convert(dbc->env->tds_ctx, src_type, src, len, dest_type, (CONV_RESULT*) dest); break; default: case XSYBNVARCHAR: case XSYBNCHAR: case SYBNVARCHAR: case SYBNTEXT: case SYBVOID: case SYBVARIANT: /* TODO ODBC 3.5 */ assert(0); res = -1; break; } if (res < 0) return SQL_ERROR; curcol->column_cur_size = res; return SQL_SUCCESS; }
static SQLLEN _tdsodbc_dbconvert(TDS_DBC *dbc, int srctype, const TDS_CHAR * src, SQLLEN src_len, int desttype, BYTE * dest, TDSCOLUMN *bindcol) { CONV_RESULT dres; SQLLEN ret; SQLLEN len; SQLLEN destlen = bindcol->column_size; TDS_DATETIMEALL dta; TDS_NUMERIC num; SQL_NUMERIC_STRUCT * sql_num; int always_convert = 0; assert(src_len >= 0); assert(src != NULL); assert(dest != NULL); assert(destlen > 0); tdsdump_log(TDS_DBG_FUNC, "tdsodbc_dbconvert(%p, %d, %p, %d, %d, %p, %d)\n", dbc, srctype, src, (int)src_len, desttype, dest, (int)destlen); switch (srctype) { case SYBMSDATETIME2: convert_datetime2server(SQL_C_TYPE_TIMESTAMP, src, &dta); dta.time_prec = (destlen - 40) / 2; src = (char *) &dta; break; case SYBDECIMAL: case SYBNUMERIC: sql_num = (SQL_NUMERIC_STRUCT *) src; num.precision = sql_num->precision; num.scale = sql_num->scale; num.array[0] = sql_num->sign ^ 1; /* test precision so client do not crash our library */ if (num.precision <= 0 || num.precision > 38 || num.scale > num.precision) /* TODO add proper error */ return -1; len = tds_numeric_bytes_per_prec[num.precision]; memcpy(num.array + 1, sql_num->val, len - 1); tds_swap_bytes(num.array + 1, len - 1); if (len < sizeof(num.array)) memset(num.array + len, 0, sizeof(num.array) - len); src = (char *) # always_convert = num.scale != bindcol->column_scale; break; /* TODO intervals */ } /* oft times we are asked to convert a data type to itself */ if ((srctype == desttype || is_similar_type(srctype, desttype)) && !always_convert) { if (is_char_type(desttype)) { ret = _bcp_iconv_helper(dbc, bindcol, src, src_len, (char *)dest, destlen); } else { ret = destlen < src_len ? destlen : src_len; memcpy(dest, src, ret); } return ret; } tdsdump_log(TDS_DBG_INFO1, "dbconvert() calling tds_convert\n"); if (is_numeric_type(desttype)) { dres.n.precision = bindcol->column_prec; dres.n.scale = bindcol->column_scale; } len = tds_convert(dbc->env->tds_ctx, srctype, src, src_len, desttype, &dres); tdsdump_log(TDS_DBG_INFO1, "dbconvert() called tds_convert returned %d\n", (int)len); if (len < 0) { odbc_convert_err_set(&dbc->errs, len); return -1; } switch (desttype) { case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: ret = destlen < len ? destlen : len; memcpy(dest, dres.ib, ret); free(dres.ib); break; case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBREAL: case SYBBIT: case SYBBITN: case SYBMONEY: case SYBMONEY4: case SYBDATETIME: case SYBDATETIME4: case SYBNUMERIC: case SYBDECIMAL: case SYBUNIQUE: case SYBMSDATE: case SYBMSTIME: case SYBMSDATETIME2: case SYBMSDATETIMEOFFSET: memcpy(dest, &dres, len); ret = len; break; case SYBCHAR: case SYBVARCHAR: case SYBTEXT: ret = _bcp_iconv_helper(dbc, bindcol, dres.c, len, (char *)dest, destlen); free(dres.c); break; default: tdsdump_log(TDS_DBG_INFO1, "error: dbconvert(): unrecognized desttype %d \n", desttype); ret = -1; break; } return (ret); }