void tds_send_col_info(TDSSOCKET * tds, TDSRESULTINFO * resinfo) { int col, hdrsize = 0; TDSCOLUMN *curcol; tds_put_byte(tds, TDS_COLFMT_TOKEN); for (col = 0; col < resinfo->num_cols; col++) { curcol = resinfo->columns[col]; hdrsize += 5; if (!is_fixed_type(curcol->column_type)) { hdrsize++; } } tds_put_smallint(tds, hdrsize); for (col = 0; col < resinfo->num_cols; col++) { curcol = resinfo->columns[col]; tds_put_n(tds, "\0\0\0\0", 4); tds_put_byte(tds, curcol->column_type); if (!is_fixed_type(curcol->column_type)) { tds_put_byte(tds, curcol->column_size); } } }
void tds_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo) { TDSCOLUMN *curcol; int i, totlen; size_t len; tds_put_byte(tds, TDS_RESULT_TOKEN); totlen = 2; for (i = 0; i < resinfo->num_cols; i++) { curcol = resinfo->columns[i]; len = tds_dstr_len(&curcol->column_name); totlen += 8; totlen += len; curcol = resinfo->columns[i]; if (!is_fixed_type(curcol->column_type)) { totlen++; } } tds_put_smallint(tds, totlen); tds_put_smallint(tds, resinfo->num_cols); for (i = 0; i < resinfo->num_cols; i++) { curcol = resinfo->columns[i]; len = tds_dstr_len(&curcol->column_name); tds_put_byte(tds, tds_dstr_len(&curcol->column_name)); tds_put_n(tds, tds_dstr_cstr(&curcol->column_name), len); tds_put_byte(tds, '0'); tds_put_int(tds, curcol->column_usertype); tds_put_byte(tds, curcol->column_type); if (!is_fixed_type(curcol->column_type)) { tds_put_byte(tds, curcol->column_size); } tds_put_byte(tds, 0); } }
static CborError advance_recursive(CborValue *it, int nestingLevel) { if (is_fixed_type(it->type)) return advance_internal(it); if (!cbor_value_is_container(it)) { size_t len = SIZE_MAX; return _cbor_value_copy_string(it, NULL, &len, it); } // map or array if (nestingLevel == CBOR_PARSER_MAX_RECURSIONS) return CborErrorNestingTooDeep; CborError err; CborValue recursed; err = cbor_value_enter_container(it, &recursed); if (err) return err; while (!cbor_value_at_end(&recursed)) { err = advance_recursive(&recursed, nestingLevel + 1); if (err) return err; } return cbor_value_leave_container(it, &recursed); }
static int read_row(TDS_POOL_MEMBER * pmbr, const unsigned char *buf, int maxlen, int *bytes_read) { TDSCOLUMN *curcol; TDSRESULTINFO *info; int i, colsize; int pos = 1; /* skip marker */ info = pmbr->tds->res_info; die_if((!info), "Entered read_row() without a res_info structure."); for (i = 0; i < info->num_cols; i++) { curcol = info->columns[i]; if (!is_fixed_type(curcol->column_type)) { if (bytes_left(pmbr, buf, pos, maxlen, 1)) { *bytes_read = maxlen; return 0; } colsize = buf[pos++]; } else { colsize = tds_get_size_by_type(curcol->column_type); } if (bytes_left(pmbr, buf, pos, maxlen, colsize)) { *bytes_read = maxlen; return 0; } pos += colsize; } *bytes_read = pos; return 1; }
/** * \ingroup odbc_bcp * \brief Bind a program host variable to a database column * * \param dbc ODBC database connection object * \param varaddr address of host variable * \param prefixlen length of any prefix found at the beginning of \a varaddr, in bytes. * Use zero for fixed-length datatypes. * \param varlen bytes of data in \a varaddr. Zero for NULL, -1 for fixed-length datatypes. * \param terminator byte sequence that marks the end of the data in \a varaddr * \param termlen length of \a terminator * \param vartype datatype of the host variable * \param table_column Nth column, starting at 1, in the table. * * \remarks The order of operation is: * - bcp_init() with \a hfile == NULL and \a direction == DB_IN. * - bcp_bind(), once per column you want to write to * - bcp_batch(), optionally, to commit a set of rows * - bcp_done() * * \sa odbc_bcp_batch(), odbc_bcp_done(), odbc_bcp_sendrow() */ void odbc_bcp_bind(TDS_DBC *dbc, const BYTE * varaddr, int prefixlen, int varlen, const BYTE * terminator, int termlen, int vartype, int table_column) { TDSCOLUMN *colinfo; tdsdump_log(TDS_DBG_FUNC, "bcp_bind(%p, %p, %d, %d -- %p, %d, %d, %d)\n", dbc, varaddr, prefixlen, varlen, terminator, termlen, vartype, table_column); if (!dbc->bcpinfo) ODBCBCP_ERROR_RETURN("HY010"); if (dbc->bcpinfo->direction != BCP_DIRECTION_IN) ODBCBCP_ERROR_RETURN("HY010"); if (varlen < -1 && varlen != SQL_VARLEN_DATA) ODBCBCP_ERROR_RETURN("HY009"); if (prefixlen != 0 && prefixlen != 1 && prefixlen != 2 && prefixlen != 4 && prefixlen != 8) ODBCBCP_ERROR_RETURN("HY009"); if (prefixlen == 0 && varlen == SQL_VARLEN_DATA && termlen == -1 && !is_fixed_type(vartype)) { tdsdump_log(TDS_DBG_FUNC, "bcp_bind(): non-fixed type %d requires prefix or terminator\n", vartype); ODBCBCP_ERROR_RETURN("HY009"); } if (table_column <= 0 || table_column > dbc->bcpinfo->bindinfo->num_cols) ODBCBCP_ERROR_RETURN("HY009"); if (varaddr == NULL && (prefixlen != 0 || termlen != 0)) ODBCBCP_ERROR_RETURN("HY009"); colinfo = dbc->bcpinfo->bindinfo->columns[table_column - 1]; /* If varaddr is NULL and varlen greater than 0, the table column type must be SYBTEXT or SYBIMAGE and the program variable type must be SYBTEXT, SYBCHAR, SYBIMAGE or SYBBINARY */ if (varaddr == NULL && varlen >= 0) { int fOK = (colinfo->column_type == SYBTEXT || colinfo->column_type == SYBIMAGE) && (vartype == SYBTEXT || vartype == SYBCHAR || vartype == SYBIMAGE || vartype == SYBBINARY ); if( !fOK ) { tdsdump_log(TDS_DBG_FUNC, "bcp_bind: SYBEBCBNTYP: column=%d and vartype=%d (should fail?)\n", colinfo->column_type, vartype); ODBCBCP_ERROR_RETURN("HY009"); } } colinfo->column_varaddr = (char *)varaddr; colinfo->column_bindtype = vartype; colinfo->column_bindlen = varlen; TDS_ZERO_FREE(colinfo->bcp_terminator); colinfo->bcp_term_len = 0; if (termlen) { if ((colinfo->bcp_terminator = (TDS_CHAR*) malloc(termlen)) == NULL) ODBCBCP_ERROR_RETURN("HY001"); memcpy(colinfo->bcp_terminator, terminator, termlen); colinfo->bcp_term_len = termlen; } }
/** * Advances the CBOR value \a it by one fixed-size position. Fixed-size types * are: integers, tags, simple types (including boolean, null and undefined * values) and floating point types. * * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse() */ CborError cbor_value_advance_fixed(CborValue *it) { assert(it->type != CborInvalidType); assert(is_fixed_type(it->type)); if (!it->remaining) return CborErrorAdvancePastEOF; return advance_internal(it); }
static int read_col_info(TDS_POOL_MEMBER * pmbr, const unsigned char *buf, int maxlen, int *bytes_read) { TDS_SMALLINT hdrsize; int pos = 0; int col, rest; TDSCOLUMN *curcol; TDSRESULTINFO *info; TDSSOCKET *tds = pmbr->tds; /* header size */ if (bytes_left(pmbr, buf, pos, maxlen, 3)) { *bytes_read = maxlen; return 0; } /* FIX ME -- endian */ hdrsize = buf[1] + buf[2] * 256; pos += 3; info = tds->res_info; for (col = 0; col < info->num_cols; col++) { curcol = info->columns[col]; if (bytes_left(pmbr, buf, pos, maxlen, 5)) { *bytes_read = maxlen; return 0; } pos += 4; curcol->column_type = buf[pos++]; /* FIX ME -- blob types */ if (!is_fixed_type(curcol->column_type)) { if (bytes_left(pmbr, buf, pos, maxlen, 1)) { *bytes_read = maxlen; return 0; } curcol->column_size = buf[pos++]; } else { curcol->column_size = tds_get_size_by_type(curcol->column_type); } } rest = hdrsize + 3 - pos; if (rest > 0) { if (bytes_left(pmbr, buf, pos, maxlen, rest)) { *bytes_read = maxlen; return 0; } fprintf(stderr, "read_col_info: draining %d bytes\n", rest); pos += rest; } *bytes_read = pos; return 1; }
void tds_send_row(TDSSOCKET * tds, TDSRESULTINFO * resinfo) { TDSCOLUMN *curcol; int colsize, i; tds_put_byte(tds, TDS_ROW_TOKEN); for (i = 0; i < resinfo->num_cols; i++) { curcol = resinfo->columns[i]; if (!is_fixed_type(curcol->column_type)) { /* FIX ME -- I have no way of knowing the actual length of non character variable data (eg nullable int) */ colsize = strlen((char *) curcol->column_data); tds_put_byte(tds, colsize); tds_put_n(tds, curcol->column_data, colsize); } else { tds_put_n(tds, curcol->column_data, tds_get_size_by_type(curcol->column_type)); } } }
CS_RETCODE cs_convert(CS_CONTEXT * ctx, CS_DATAFMT * srcfmt, CS_VOID * srcdata, CS_DATAFMT * destfmt, CS_VOID * destdata, CS_INT * resultlen) { int src_type, src_len, desttype, destlen, len, i = 0; CONV_RESULT cres; unsigned char *dest; CS_RETCODE ret; CS_INT dummy; CS_VARCHAR *destvc = NULL; tdsdump_log(TDS_DBG_FUNC, "cs_convert(%p, %p, %p, %p, %p, %p)\n", ctx, srcfmt, srcdata, destfmt, destdata, resultlen); /* If destination is NULL we have a problem */ if (destdata == NULL) { /* TODO: add error message */ tdsdump_log(TDS_DBG_FUNC, "error: destdata is null\n"); return CS_FAIL; } /* If destfmt is NULL we have a problem */ if (destfmt == NULL) { /* TODO: add error message */ tdsdump_log(TDS_DBG_FUNC, "error: destfmt is null\n"); return CS_FAIL; } if (resultlen == NULL) resultlen = &dummy; /* If source is indicated to be NULL, set dest to low values */ if (srcdata == NULL) { /* TODO: implement cs_setnull */ tdsdump_log(TDS_DBG_FUNC, "srcdata is null\n"); memset(destdata, '\0', destfmt->maxlength); *resultlen = 0; return CS_SUCCEED; } src_type = _ct_get_server_type(srcfmt->datatype); src_len = srcfmt->maxlength; if (srcfmt->datatype == CS_VARCHAR_TYPE || srcfmt->datatype == CS_VARBINARY_TYPE) { CS_VARCHAR *vc = (CS_VARCHAR *) srcdata; src_len = vc->len; srcdata = vc->str; } desttype = _ct_get_server_type(destfmt->datatype); destlen = destfmt->maxlength; if (destfmt->datatype == CS_VARCHAR_TYPE || destfmt->datatype == CS_VARBINARY_TYPE) { destvc = (CS_VARCHAR *) destdata; destlen = sizeof(destvc->str); destdata = destvc->str; } tdsdump_log(TDS_DBG_FUNC, "converting type %d (%d bytes) to type = %d (%d bytes)\n", src_type, src_len, desttype, destlen); if (!is_fixed_type(desttype) && (destlen <= 0)) { return CS_FAIL; } dest = (unsigned char *) destdata; /* many times we are asked to convert a data type to itself */ if (src_type == desttype) { int minlen = src_len < destlen? src_len : destlen; tdsdump_log(TDS_DBG_FUNC, "cs_convert() srctype == desttype\n"); switch (desttype) { case SYBLONGBINARY: case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: memcpy(dest, srcdata, src_len); *resultlen = src_len; if (src_len > destlen) { tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n"); ret = CS_FAIL; } else { switch (destfmt->format) { case CS_FMT_PADNULL: memset(dest + src_len, '\0', destlen - src_len); *resultlen = destlen; /* fall through */ case CS_FMT_UNUSED: ret = CS_SUCCEED; break; default: ret = CS_FAIL; break; } } if (destvc) { destvc->len = minlen; *resultlen = sizeof(*destvc); } break; case SYBCHAR: case SYBVARCHAR: case SYBTEXT: tdsdump_log(TDS_DBG_FUNC, "cs_convert() desttype = character\n"); memcpy(dest, srcdata, minlen); *resultlen = minlen; if (src_len > destlen) { tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n"); ret = CS_FAIL; } else { switch (destfmt->format) { case CS_FMT_NULLTERM: if (src_len == destlen) { *resultlen = src_len; tdsdump_log(TDS_DBG_FUNC, "error: no room for null terminator\n"); ret = CS_FAIL; } else { dest[src_len] = '\0'; *resultlen = src_len + 1; ret = CS_SUCCEED; } break; case CS_FMT_PADBLANK: memset(dest + src_len, ' ', destlen - src_len); *resultlen = destlen; ret = CS_SUCCEED; break; case CS_FMT_PADNULL: memset(dest + src_len, '\0', destlen - src_len); *resultlen = destlen; ret = CS_SUCCEED; break; case CS_FMT_UNUSED: ret = CS_SUCCEED; break; default: tdsdump_log(TDS_DBG_FUNC, "no destination format specified!\n"); ret = CS_FAIL; break; } } if (destvc) { destvc->len = minlen; *resultlen = sizeof(*destvc); } break; case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBFLT8: case SYBREAL: case SYBBIT: case SYBMONEY: case SYBMONEY4: case SYBDATETIME: case SYBDATETIME4: *resultlen = _cs_datatype_length(src_type); memcpy(dest, srcdata, *resultlen); ret = CS_SUCCEED; break; case SYBNUMERIC: case SYBDECIMAL: src_len = tds_numeric_bytes_per_prec[((TDS_NUMERIC *) srcdata)->precision] + 2; case SYBBITN: memcpy(dest, srcdata, minlen); *resultlen = minlen; if (src_len > destlen) { tdsdump_log(TDS_DBG_FUNC, "error: src_len > destlen\n"); ret = CS_FAIL; } else { ret = CS_SUCCEED; } break; default: tdsdump_log(TDS_DBG_FUNC, "error: unrecognized type\n"); ret = CS_FAIL; break; } tdsdump_log(TDS_DBG_FUNC, "cs_convert() returning %s\n", cs_prretcode(ret)); return ret; } assert(src_type != desttype); /* set the output precision/scale for conversions to numeric type */ if (is_numeric_type(desttype)) { cres.n.precision = destfmt->precision; cres.n.scale = destfmt->scale; if (destfmt->precision == CS_SRC_VALUE) cres.n.precision = srcfmt->precision; if (destfmt->scale == CS_SRC_VALUE) cres.n.scale = srcfmt->scale; } tdsdump_log(TDS_DBG_FUNC, "cs_convert() calling tds_convert\n"); len = tds_convert(ctx->tds_ctx, src_type, (TDS_CHAR*) srcdata, src_len, desttype, &cres); tdsdump_log(TDS_DBG_FUNC, "cs_convert() tds_convert returned %d\n", len); switch (len) { case TDS_CONVERT_NOAVAIL: _csclient_msg(ctx, "cs_convert", 2, 1, 1, 16, "%d, %d", src_type, desttype); return CS_FAIL; break; case TDS_CONVERT_SYNTAX: _csclient_msg(ctx, "cs_convert", 2, 4, 1, 24, ""); return CS_FAIL; break; case TDS_CONVERT_NOMEM: _csclient_msg(ctx, "cs_convert", 2, 4, 1, 3, ""); return CS_FAIL; break; case TDS_CONVERT_OVERFLOW: _csclient_msg(ctx, "cs_convert", 2, 4, 1, 20, ""); return CS_FAIL; break; case TDS_CONVERT_FAIL: return CS_FAIL; break; default: if (len < 0) { return CS_FAIL; } break; } switch (desttype) { case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: ret = CS_SUCCEED; if (len > destlen) { tdsdump_log(TDS_DBG_FUNC, "error_handler: Data-conversion resulted in overflow\n"); ret = CS_FAIL; len = destlen; } memcpy(dest, cres.ib, len); free(cres.ib); *resultlen = destlen; if (destvc) { destvc->len = len; *resultlen = sizeof(*destvc); } for (i = len; i < destlen; i++) dest[i] = '\0'; break; case SYBBIT: case SYBBITN: /* fall trough, act same way of TINYINT */ case SYBINT1: memcpy(dest, &(cres.ti), 1); *resultlen = 1; ret = CS_SUCCEED; break; case SYBINT2: memcpy(dest, &(cres.si), 2); *resultlen = 2; ret = CS_SUCCEED; break; case SYBINT4: memcpy(dest, &(cres.i), 4); *resultlen = 4; ret = CS_SUCCEED; break; case SYBINT8: memcpy(dest, &(cres.bi), 8); *resultlen = 8; ret = CS_SUCCEED; break; case SYBFLT8: memcpy(dest, &(cres.f), 8); *resultlen = 8; ret = CS_SUCCEED; break; case SYBREAL: memcpy(dest, &(cres.r), 4); *resultlen = 4; ret = CS_SUCCEED; break; case SYBMONEY: tdsdump_log(TDS_DBG_FUNC, "cs_convert() copying %d bytes to src\n", (int) sizeof(TDS_MONEY)); memcpy(dest, &(cres.m), sizeof(TDS_MONEY)); *resultlen = sizeof(TDS_MONEY); ret = CS_SUCCEED; break; case SYBMONEY4: memcpy(dest, &(cres.m4), sizeof(TDS_MONEY4)); *resultlen = sizeof(TDS_MONEY4); ret = CS_SUCCEED; break; case SYBDATETIME: memcpy(dest, &(cres.dt), sizeof(TDS_DATETIME)); *resultlen = sizeof(TDS_DATETIME); ret = CS_SUCCEED; break; case SYBDATETIME4: memcpy(dest, &(cres.dt4), sizeof(TDS_DATETIME4)); *resultlen = sizeof(TDS_DATETIME4); ret = CS_SUCCEED; break; case SYBNUMERIC: case SYBDECIMAL: src_len = tds_numeric_bytes_per_prec[cres.n.precision] + 2; memcpy(dest, &(cres.n), src_len); *resultlen = src_len; ret = CS_SUCCEED; break; case SYBCHAR: case SYBVARCHAR: case SYBTEXT: ret = CS_SUCCEED; if (len > destlen) { tdsdump_log(TDS_DBG_FUNC, "Data-conversion resulted in overflow\n"); len = destlen; ret = CS_FAIL; } switch (destfmt->format) { case CS_FMT_NULLTERM: tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_NULLTERM\n"); if (len == destlen) { tdsdump_log(TDS_DBG_FUNC, "not enough room for data + a null terminator - error\n"); ret = CS_FAIL; /* not enough room for data + a null terminator - error */ } else { memcpy(dest, cres.c, len); dest[len] = 0; *resultlen = len + 1; } break; case CS_FMT_PADBLANK: tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADBLANK\n"); /* strcpy here can lead to a small buffer overflow */ memcpy(dest, cres.c, len); for (i = len; i < destlen; i++) dest[i] = ' '; *resultlen = destlen; break; case CS_FMT_PADNULL: tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_PADNULL\n"); /* strcpy here can lead to a small buffer overflow */ memcpy(dest, cres.c, len); for (i = len; i < destlen; i++) dest[i] = '\0'; *resultlen = destlen; break; case CS_FMT_UNUSED: tdsdump_log(TDS_DBG_FUNC, "cs_convert() FMT_UNUSED\n"); memcpy(dest, cres.c, len); *resultlen = len; break; default: ret = CS_FAIL; break; } if (destvc) { destvc->len = len; *resultlen = sizeof(*destvc); } free(cres.c); break; default: ret = CS_FAIL; break; } tdsdump_log(TDS_DBG_FUNC, "cs_convert() returning %s\n", cs_prretcode(ret)); return (ret); }
void tds_check_column_extra(const TDSCOLUMN * column) { int size; TDSCONNECTION conn; int varint_ok; int column_varint_size; assert(column); column_varint_size = column->column_varint_size; /* 8 is for varchar(max) or similar */ assert(column_varint_size == 8 || (column_varint_size <= 5 && column_varint_size != 3)); assert(column->column_scale <= column->column_prec); assert(column->column_prec <= MAXPRECISION); /* I don't like this that much... freddy77 */ if (column->column_type == 0) return; assert(column->funcs); assert(column->column_type > 0); /* check type and server type same or SQLNCHAR -> SQLCHAR */ #define SPECIAL(ttype, server_type, varint) \ if (column->column_type == ttype && column->on_server.column_type == server_type && column_varint_size == varint) {} else SPECIAL(SYBTEXT, XSYBVARCHAR, 8) SPECIAL(SYBTEXT, XSYBNVARCHAR, 8) SPECIAL(SYBIMAGE, XSYBVARBINARY, 8) assert(tds_get_cardinal_type(column->on_server.column_type, column->column_usertype) == column->column_type || (tds_get_conversion_type(column->on_server.column_type, column->column_size) == column->column_type && column_varint_size == 1 && is_fixed_type(column->column_type))); varint_ok = 0; if (column_varint_size == 8) { assert(column->on_server.column_type == XSYBVARCHAR || column->on_server.column_type == XSYBVARBINARY || column->on_server.column_type == XSYBNVARCHAR || column->on_server.column_type == SYBMSXML || column->on_server.column_type == SYBMSUDT); varint_ok = 1; } else if (is_blob_type(column->column_type)) { assert(column_varint_size >= 4); } else if (column->column_type == SYBVARIANT) { assert(column_varint_size == 4); } conn.tds_version = 0x500; varint_ok = varint_ok || tds_get_varint_size(&conn, column->on_server.column_type) == column_varint_size; conn.tds_version = 0x700; varint_ok = varint_ok || tds_get_varint_size(&conn, column->on_server.column_type) == column_varint_size; assert(varint_ok); /* check current size <= size */ if (is_numeric_type(column->column_type)) { /* I don't like that much this difference between numeric and not numeric - freddy77 */ /* TODO what should be the size ?? */ assert(column->column_prec >= 1 && column->column_prec <= MAXPRECISION); assert(column->column_scale <= column->column_prec); /* assert(column->column_cur_size == tds_numeric_bytes_per_prec[column->column_prec] + 2 || column->column_cur_size == -1); */ } else { assert(column->column_cur_size <= column->column_size); } /* check size of fixed type correct */ size = tds_get_size_by_type(column->column_type); assert(size != 0 || column->column_type == SYBVOID); if (size >= 0 && column->column_type != SYBBITN) { /* check macro */ assert(is_fixed_type(column->column_type)); /* check current size */ if (column->column_type != SYBMSDATE) assert(size == column->column_size); /* check cases where server need nullable types */ if (column->column_type != column->on_server.column_type && (column->column_type != SYBINT8 || column->on_server.column_type != SYB5INT8)) { assert(!is_fixed_type(column->on_server.column_type)); assert(column_varint_size == 1); assert(column->column_size == column->column_cur_size || column->column_cur_size == -1); } else { assert(column_varint_size == 0 || (column->column_type == SYBUNIQUE && column_varint_size == 1) || (column->column_type == SYBMSDATE && column_varint_size == 1)); assert(column->column_size == column->column_cur_size || (column->column_type == SYBUNIQUE && column->column_cur_size == -1) || (column->column_type == SYBMSDATE && column->column_cur_size == -1)); } assert(column->column_size == column->on_server.column_size); } else { assert(!is_fixed_type(column->column_type)); assert(is_char_type(column->column_type) || (column->on_server.column_size == column->column_size || column->on_server.column_size == 0)); assert(column_varint_size != 0); } /* check size of nullable types (ie intN) it's supported */ if (tds_get_conversion_type(column->column_type, 4) != column->column_type) { /* check macro */ assert(is_nullable_type(column->column_type)); /* check that size it's correct for this type of nullable */ assert(tds_get_conversion_type(column->column_type, column->column_size) != column->column_type); /* check current size */ assert(column->column_size >= column->column_cur_size || column->column_cur_size == -1); /* check same type and size on server */ assert(column->column_type == column->on_server.column_type); assert(column->column_size == column->on_server.column_size); } }
static CborError preparse_value(CborValue *it) { const CborParser *parser = it->parser; it->type = CborInvalidType; // are we at the end? if (it->ptr == parser->end) return CborErrorUnexpectedEOF; uint8_t descriptor = *it->ptr; uint8_t type = descriptor & MajorTypeMask; it->type = type; it->flags = 0; it->extra = (descriptor &= SmallValueMask); if (descriptor > Value64Bit) { if (unlikely(descriptor != IndefiniteLength)) return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber; if (likely(!is_fixed_type(type))) { // special case it->flags |= CborIteratorFlag_UnknownLength; it->type = type; return CborNoError; } return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber; } size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit)); if (it->ptr + 1 + bytesNeeded > parser->end) return CborErrorUnexpectedEOF; uint8_t majortype = type >> MajorTypeShift; if (majortype == NegativeIntegerType) { it->flags |= CborIteratorFlag_NegativeInteger; it->type = CborIntegerType; } else if (majortype == SimpleTypesType) { switch (descriptor) { case FalseValue: it->extra = false; it->type = CborBooleanType; break; case SinglePrecisionFloat: case DoublePrecisionFloat: it->flags |= CborIteratorFlag_IntegerValueTooLarge; // fall through case TrueValue: case NullValue: case UndefinedValue: case HalfPrecisionFloat: it->type = *it->ptr; break; case SimpleTypeInNextByte: it->extra = (uint8_t)it->ptr[1]; #ifndef CBOR_PARSER_NO_STRICT_CHECKS if (unlikely(it->extra < 32)) { it->type = CborInvalidType; return CborErrorIllegalSimpleType; } #endif break; case 28: case 29: case 30: case Break: assert(false); // these conditions can't be reached return CborErrorUnexpectedBreak; } return CborNoError; } // try to decode up to 16 bits if (descriptor < Value8Bit) return CborNoError; if (descriptor == Value8Bit) it->extra = (uint8_t)it->ptr[1]; else if (descriptor == Value16Bit) it->extra = get16(it->ptr + 1); else it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit return CborNoError; }
/** * \ingroup dblib_rpc * \brief Add a parameter to a remote procedure call. * Call between dbrpcinit() and dbrpcsend() * \param dbproc contains all information needed by db-lib to manage communications with the server. * \param paramname literal name of the parameter, according to the stored procedure (starts with '@'). Optional. * If not used, parameters will be passed in order instead of by name. * \param status must be DBRPCRETURN, if this parameter is a return parameter, else 0. * \param type datatype of the value parameter e.g., SYBINT4, SYBCHAR. * \param maxlen Maximum output size of the parameter's value to be returned by the stored procedure, usually the size of your host variable. * Fixed-length datatypes take -1 (NULL or not). * Non-OUTPUT parameters also use -1. * Use 0 to send a NULL value for a variable length datatype. * \param datalen For variable-length datatypes, the byte size of the data to be sent, exclusive of any null terminator. * For fixed-length datatypes use -1. To send a NULL value, use 0. * \param value Address of your host variable. * \retval SUCCEED normal. * \retval FAIL on error * \sa dbrpcinit(), dbrpcsend() */ RETCODE dbrpcparam(DBPROCESS * dbproc, char *paramname, BYTE status, int type, DBINT maxlen, DBINT datalen, BYTE * value) { char *name = NULL; DBREMOTE_PROC *rpc; DBREMOTE_PROC_PARAM **pparam; DBREMOTE_PROC_PARAM *param; /* sanity */ if (dbproc == NULL) return FAIL; if (dbproc->rpc == NULL) return FAIL; /* validate datalen parameter */ if (is_fixed_type(type)) { if (datalen > 0) return FAIL; } else { if (datalen < 0) return FAIL; } /* validate maxlen parameter */ if (status & DBRPCRETURN) { if (is_fixed_type(type)) { if (maxlen != -1) return FAIL; } else { if (maxlen == -1) maxlen = 255; } } else { /* * Well, maxlen should be used only for output parameter however it seems * that ms implementation wrongly require this 0 for NULL variable * input parameters, so fix it */ if (maxlen != -1 && maxlen != 0) return FAIL; maxlen = -1; } /* TODO add other tests for correctness */ /* allocate */ param = (DBREMOTE_PROC_PARAM *) malloc(sizeof(DBREMOTE_PROC_PARAM)); if (param == NULL) return FAIL; if (paramname) { name = strdup(paramname); if (name == NULL) { free(param); return FAIL; } } /* initialize */ param->next = NULL; /* NULL signifies end of linked list */ param->name = name; param->status = status; param->type = type; param->maxlen = maxlen; param->datalen = datalen; /* * if datalen = 0, value parameter is ignored * this is one way to specify a NULL input parameter */ if (datalen == 0) param->value = NULL; else param->value = value; /* * Add a parameter to the current rpc. * * Traverse the dbproc's procedure list to find the current rpc, * then traverse the parameter linked list until its end, * then tack on our parameter's address. */ for (rpc = dbproc->rpc; rpc->next != NULL; rpc = rpc->next) /* find "current" procedure */ ; for (pparam = &rpc->param_list; *pparam != NULL; pparam = &(*pparam)->next); /* pparam now contains the address of the end of the rpc's parameter list */ *pparam = param; /* add to the end of the list */ tdsdump_log(TDS_DBG_INFO1, "dbrpcparam() added parameter \"%s\"\n", (paramname) ? paramname : ""); return SUCCEED; }
/** * Allocate memory and copy the rpc information into a TDSPARAMINFO structure. */ static TDSPARAMINFO * param_info_alloc(TDSSOCKET * tds, DBREMOTE_PROC * rpc) { int i; DBREMOTE_PROC_PARAM *p; TDSCOLUMN *pcol; TDSPARAMINFO *params = NULL, *new_params; BYTE *temp_value; int temp_datalen; int temp_type; int param_is_null; /* sanity */ if (rpc == NULL) return NULL; /* see v 1.10 2002/11/23 for first broken attempt */ for (i = 0, p = rpc->param_list; p != NULL; p = p->next, i++) { const unsigned char *prow; if (!(new_params = tds_alloc_param_result(params))) { tds_free_param_results(params); tdsdump_log(TDS_DBG_ERROR, "out of rpc memory!"); return NULL; } params = new_params; /* * Determine whether an input parameter is NULL * or not. */ param_is_null = 0; temp_type = p->type; temp_value = p->value; temp_datalen = p->datalen; if (p->datalen == 0) param_is_null = 1; tdsdump_log(TDS_DBG_INFO1, "parm_info_alloc(): parameter null-ness = %d\n", param_is_null); if (param_is_null || (p->status & DBRPCRETURN)) { if (param_is_null) { temp_datalen = 0; temp_value = NULL; } else if (is_fixed_type(temp_type)) { temp_datalen = tds_get_size_by_type(temp_type); } temp_type = tds_get_null_type(temp_type); } else if (is_fixed_type(temp_type)) { temp_datalen = tds_get_size_by_type(temp_type); } pcol = params->columns[i]; /* meta data */ if (p->name) { tds_strlcpy(pcol->column_name, p->name, sizeof(pcol->column_name)); pcol->column_namelen = strlen(pcol->column_name); } tds_set_param_type(tds, pcol, temp_type); if (p->maxlen > 0) pcol->column_size = p->maxlen; else { if (is_fixed_type(p->type)) { pcol->column_size = tds_get_size_by_type(p->type); } else { pcol->column_size = p->datalen; } } pcol->on_server.column_size = pcol->column_size; pcol->column_output = p->status; pcol->column_cur_size = temp_datalen; prow = param_row_alloc(params, pcol, i, temp_value, temp_datalen); if (!prow) { tds_free_param_results(params); tdsdump_log(TDS_DBG_ERROR, "out of memory for rpc row!"); return NULL; } } return params; }
/** * 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; }
void tds_check_column_extra(const TDSCOLUMN * column) { int size; TDSCONNECTION conn; int varint_ok; int column_varint_size; assert(column); column_varint_size = column->column_varint_size; /* 8 is for varchar(max) or similar */ assert(column_varint_size == 8 || (column_varint_size <= 5 && column_varint_size != 3)); assert(column->column_scale <= column->column_prec); assert(column->column_prec <= MAXPRECISION); /* I don't like this that much... freddy77 */ if (column->column_type == 0) return; assert(column->funcs); assert(column->column_type > 0); /* specific checks, if true fully checked */ if (column->funcs->check(column)) return; /* check type and server type same or SQLNCHAR -> SQLCHAR */ #define SPECIAL(ttype, server_type, varint) \ if (column->column_type == ttype && column->on_server.column_type == server_type && column_varint_size == varint) {} else SPECIAL(SYBTEXT, XSYBVARCHAR, 8) SPECIAL(SYBTEXT, XSYBNVARCHAR, 8) SPECIAL(SYBIMAGE, XSYBVARBINARY, 8) assert(tds_get_cardinal_type(column->on_server.column_type, column->column_usertype) == column->column_type || (tds_get_conversion_type(column->on_server.column_type, column->column_size) == column->column_type && column_varint_size == 1 && is_fixed_type(column->column_type))); varint_ok = 0; if (column_varint_size == 8) { if (column->on_server.column_type == XSYBVARCHAR || column->on_server.column_type == XSYBVARBINARY || column->on_server.column_type == XSYBNVARCHAR) varint_ok = 1; } else if (is_blob_type(column->column_type)) { assert(column_varint_size >= 4); } else if (column->column_type == SYBVARIANT) { assert(column_varint_size == 4); } conn.tds_version = 0x500; varint_ok = varint_ok || tds_get_varint_size(&conn, column->on_server.column_type) == column_varint_size; conn.tds_version = 0x700; varint_ok = varint_ok || tds_get_varint_size(&conn, column->on_server.column_type) == column_varint_size; assert(varint_ok); assert(!is_numeric_type(column->column_type)); assert(column->column_cur_size <= column->column_size); /* check size of fixed type correct */ size = tds_get_size_by_type(column->column_type); assert(size != 0 || column->column_type == SYBVOID); /* these peculiar types are variable but have only a possible size */ if (size >= 0 && (column->column_type != SYBBITN && column->column_type != SYBDATEN && column->column_type != SYBTIMEN)) { /* check macro */ assert(is_fixed_type(column->column_type)); /* check current size */ assert(size == column->column_size); /* check cases where server need nullable types */ if (column->column_type != column->on_server.column_type && (column->column_type != SYBINT8 || column->on_server.column_type != SYB5INT8)) { assert(!is_fixed_type(column->on_server.column_type)); assert(column_varint_size == 1); assert(column->column_size == column->column_cur_size || column->column_cur_size == -1); } else { assert(column_varint_size == 0 || (column->column_type == SYBUNIQUE && column_varint_size == 1)); assert(column->column_size == column->column_cur_size || (column->column_type == SYBUNIQUE && column->column_cur_size == -1)); } assert(column->column_size == column->on_server.column_size); } else { assert(!is_fixed_type(column->column_type)); assert(is_char_type(column->column_type) || (column->on_server.column_size == column->column_size || column->on_server.column_size == 0)); assert(column_varint_size != 0); } /* check size of nullable types (ie intN) it's supported */ if (tds_get_conversion_type(column->column_type, 4) != column->column_type) { /* check macro */ assert(is_nullable_type(column->column_type)); /* check that size it's correct for this type of nullable */ assert(tds_get_conversion_type(column->column_type, column->column_size) != column->column_type); /* check current size */ assert(column->column_size >= column->column_cur_size || column->column_cur_size == -1); /* check same type and size on server */ assert(column->column_type == column->on_server.column_type); assert(column->column_size == column->on_server.column_size); } }
static TDSRET _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset) { TDS_TINYINT ti; TDS_SMALLINT si; TDS_INT li; tds_sysdep_int64_type lli; TDS_INT desttype; int coltype; SQLLEN col_len; int data_is_null; SQLLEN bytes_read; int converted_data_size; TDS_CHAR *dataptr; TDS_DBC *dbc = (TDS_DBC *) bcpinfo->parent; tdsdump_log(TDS_DBG_FUNC, "_bcp_get_col_data(%p, %p)\n", bcpinfo, bindcol); dataptr = bindcol->column_varaddr; data_is_null = 0; col_len = SQL_NULL_DATA; /* If a prefix length specified, read the correct amount of data. */ if (bindcol->bcp_prefix_len > 0) { switch (bindcol->bcp_prefix_len) { case 1: memcpy(&ti, dataptr, 1); dataptr += 1; col_len = ti; break; case 2: memcpy(&si, dataptr, 2); dataptr += 2; col_len = si; break; case 4: memcpy(&li, dataptr, 4); dataptr += 4; col_len = li; break; case 8: memcpy(&lli, dataptr, 8); dataptr += 8; col_len = lli; if (lli != col_len) return TDS_FAIL; break; } if (col_len == SQL_NULL_DATA) data_is_null = 1; } /* if (Max) column length specified take that into consideration. */ if (bindcol->column_bindlen == SQL_NULL_DATA) data_is_null = 1; else if (!data_is_null && bindcol->column_bindlen != SQL_VARLEN_DATA) { if (col_len != SQL_NULL_DATA) col_len = ((tds_sysdep_int64_type)bindcol->column_bindlen < col_len) ? bindcol->column_bindlen : col_len; else col_len = bindcol->column_bindlen; } desttype = tds_get_conversion_type(bindcol->column_type, bindcol->column_size); /* Fixed Length data - this overrides anything else specified */ coltype = bindcol->column_bindtype == 0 ? desttype : bindcol->column_bindtype; if (is_fixed_type(coltype)) { col_len = tds_get_size_by_type(coltype); } /* read the data, finally */ if (!data_is_null && bindcol->bcp_term_len > 0) { /* terminated field */ bytes_read = _bcp_get_term_var(dataptr, bindcol->bcp_terminator, bindcol->bcp_term_len); if (col_len != SQL_NULL_DATA) col_len = (bytes_read < col_len) ? bytes_read : col_len; else col_len = bytes_read; } if (data_is_null) { bindcol->bcp_column_data->datalen = 0; bindcol->bcp_column_data->is_null = 1; } else { if ((converted_data_size = _tdsodbc_dbconvert(dbc, coltype, dataptr, col_len, desttype, bindcol->bcp_column_data->data, bindcol)) == -1) { return TDS_FAIL; } bindcol->bcp_column_data->datalen = converted_data_size; bindcol->bcp_column_data->is_null = 0; assert(converted_data_size > 0); } return TDS_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; }