/** * Tell the TDSPARAMINFO structure where the data go. This is a kind of "bind" operation. */ static const unsigned char * param_row_alloc(TDSPARAMINFO * params, TDSCOLUMN * curcol, int param_num, void *value, int size) { const unsigned char *row = tds_alloc_param_row(params, curcol); tdsdump_log(TDS_DBG_INFO1, "parameter size = %d, offset = %d, row_size = %d\n", size, curcol->column_offset, params->row_size); if (!row) return NULL; if (size > 0 && value) { tdsdump_log(TDS_DBG_FUNC, "copying %d bytes of data to parameter #%d\n", size, param_num); if (!is_blob_type(curcol->column_type)) { memcpy(¶ms->current_row[curcol->column_offset], value, size); } else { TDSBLOB *blob = (TDSBLOB *) ¶ms->current_row[curcol->column_offset]; blob->textvalue = malloc(size); tdsdump_log(TDS_DBG_FUNC, "blob parameter supported, size %d textvalue pointer is %p\n", size, blob->textvalue); if (!blob->textvalue) return NULL; memcpy(blob->textvalue, value, size); } } else { tdsdump_log(TDS_DBG_FUNC, "setting parameter #%d to NULL\n", param_num); curcol->column_cur_size = -1; } return row; }
/** * 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; }