void tds7_send_result(TDSSOCKET * tds, TDSRESULTINFO * resinfo) { int i, j; TDSCOLUMN *curcol; /* TDS7+ uses TDS7_RESULT_TOKEN to send column names and info */ tds_put_byte(tds, TDS7_RESULT_TOKEN); /* send the number of columns */ tds_put_smallint(tds, resinfo->num_cols); /* send info about each column */ for (i = 0; i < resinfo->num_cols; i++) { /* usertype, flags, and type */ curcol = resinfo->columns[i]; tds_put_smallint(tds, curcol->column_usertype); tds_put_smallint(tds, curcol->column_flags); tds_put_byte(tds, curcol->column_type); /* smallint? */ /* bytes in "size" field varies */ if (is_blob_type(curcol->column_type)) { tds_put_int(tds, curcol->column_size); } else if (curcol->column_type>=128) { /*is_large_type*/ tds_put_smallint(tds, curcol->column_size); } else { tds_put_tinyint(tds, curcol->column_size); } /* some types have extra info */ if (is_numeric_type(curcol->column_type)) { tds_put_tinyint(tds, curcol->column_prec); tds_put_tinyint(tds, curcol->column_scale); } else if (is_blob_type(curcol->column_type)) { size_t len = tds_dstr_len(&curcol->table_name); const char *name = tds_dstr_cstr(&curcol->table_name); tds_put_smallint(tds, 2 * len); for (j = 0; name[j] != '\0'; j++){ tds_put_byte(tds, name[j]); tds_put_byte(tds, 0); } } /* finally the name, in UCS16 format */ assert(strlen(curcol->column_name) == curcol->column_namelen); tds_put_byte(tds, curcol->column_namelen); for (j = 0; j < curcol->column_namelen; j++) { tds_put_byte(tds, curcol->column_name[j]); tds_put_byte(tds, 0); } } }
tType result_type (tOperator op, tType left, tType right, tPosition pos) { switch (op) { case op_lt: case op_le: case op_gt: case op_ge: case op_eq: case op_ne: /* relational operators */ return type_bool; case op_and: case op_or: case op_not: /* boolean operators */ return type_bool; case op_mod: /* modulo returns an integer */ return type_int; case op_pow: /* power returns a float */ return type_float; case op_plus: case op_minus: case op_mult: case op_div: /* numeric operators, return a numeric type */ if (right == type_none && is_numeric_type (left)) return left; /* unary operator */ /* binary operators */ if (is_numeric_type (left) && is_numeric_type (right)) { /* if types differ, return the "larger" type with: "INT < FLOAT" */ return (left == right) ? left : type_float; } /* may be an argument has a boolean type */ Message ("Type mismatch", xxError, pos); return type_error; default: FATAL_ERROR(); return type_error; } }
tType argument_type (tOperator op, tType left, tType right, tPosition pos) { switch (op) { case op_lt: case op_le: case op_gt: case op_ge: case op_eq: case op_ne: /* relational operators take numeric or boolean argument */ if (left == right) return left; if (is_numeric_type (left) && is_numeric_type (right)) { /* if types differ, return the "larger" type with: "INT < FLOAT" */ return (left == right)? left : type_float; } Message ("Type mismatch", xxError, pos); return type_error; case op_mod: /* arguments should be coerced to INT */ if (is_numeric_type (left) && is_numeric_type (right)) { return type_int; } Message ("Type mismatch", xxError, pos); return type_error; case op_plus: case op_minus: case op_mult: case op_div: case op_pow: /* numeric operators take numeric arguments */ if (right == type_none && is_numeric_type (left)) return left; /* unary operators */ if (is_numeric_type (left) && is_numeric_type (right)) { /* if types differ, return the "larger" type with: "INT < FLOAT" */ return (left == right)? left : type_float; } Message ("Type mismatch", xxError, pos); return type_error; case op_and: case op_or: case op_not: /* boolean operators take boolean arguments */ if (left == type_bool && (right == type_none || right == type_bool)) return type_bool; Message ("Type mismatch", xxError, pos); return type_error; default: FATAL_ERROR(); return type_error; } }
/* See XQuery 1.0 Errata for complete casting rules for general comparison */ void PPGeneralComparison::generalNodePrepare(tuple_cell& cell1, tuple_cell& cell2) { tuple_cell* untyped = &cell2; tuple_cell* typed = &cell1; if (cell1.get_atomic_type() == xs_untypedAtomic) { untyped = &cell1; typed = &cell2; } else if (cell2.get_atomic_type() != xs_untypedAtomic) { return; } xmlscm_type type = typed->get_atomic_type(); /* If both atomic values are instances of xs:untypedAtomic, then the values are cast to the type xs:string. */ if(type == xs_untypedAtomic) { *untyped = cast_primitive_to_xs_string(*untyped); *typed = cast_primitive_to_xs_string(*typed); } /* If T is an instance of a numeric type, V is cast to xs:double */ else if(is_numeric_type(type)) { *untyped = cast(*untyped, xs_double); } /* If T is xs:dayTimeDuration or is derived from xs:dayTimeDuration, * then V is cast to xs:dayTimeDuration. * If T is xs:yearMonthDuration or is derived from xs:yearMonthDuration, * then V is cast to xs:yearMonthDuration.*/ else if(type == xs_dayTimeDuration || type == xs_yearMonthDuration) { *untyped = cast(*untyped, type); } /* In all other cases, V is cast to the primitive base type of T */ else { *untyped = cast(*untyped, primitive_base_type(type)); } }
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); } }
SQLLEN odbc_tds2sql(TDS_STMT * stmt, TDSCOLUMN *curcol, int srctype, TDS_CHAR * src, TDS_UINT srclen, int desttype, TDS_CHAR * dest, SQLULEN destlen, const struct _drecord *drec_ixd) { TDS_INT nDestSybType; TDS_INT nRetVal = TDS_CONVERT_FAIL; TDSCONTEXT *context = stmt->dbc->env->tds_ctx; CONV_RESULT ores; SQLLEN ret = SQL_NULL_DATA; int i, cplen; int binary_conversion = 0; TDS_CHAR conv_buf[256]; tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: src is %d dest = %d\n", srctype, desttype); assert(desttype != SQL_C_DEFAULT); if (curcol) { if (is_blob_col(curcol)) { if (srctype == SYBLONGBINARY && ( curcol->column_usertype == USER_UNICHAR_TYPE || curcol->column_usertype == USER_UNIVARCHAR_TYPE)) srctype = SYBTEXT; if (curcol->column_type == SYBVARIANT) srctype = ((TDSVARIANT *) src)->type; src = ((TDSBLOB *) src)->textvalue; } if (is_variable_type(curcol->column_type)) { src += curcol->column_text_sqlgetdatapos; srclen -= curcol->column_text_sqlgetdatapos; } } nDestSybType = odbc_c_to_server_type(desttype); if (!nDestSybType) { odbc_errs_add(&stmt->errs, "HY003", NULL); return SQL_NULL_DATA; } /* special case for binary type */ if (desttype == SQL_C_BINARY) { tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting binary data destlen = %lu \n", (unsigned long) destlen); if (is_numeric_type(srctype)) { desttype = SQL_C_NUMERIC; nDestSybType = SYBNUMERIC; /* prevent buffer overflow */ if (destlen < sizeof(SQL_NUMERIC_STRUCT)) { odbc_errs_add(&stmt->errs, "07006", NULL); return SQL_NULL_DATA; } ores.n.precision = ((TDS_NUMERIC *) src)->precision; ores.n.scale = ((TDS_NUMERIC *) src)->scale; } else { return odbc_convert_to_binary(stmt, curcol, srctype, src, srclen, dest, destlen); } } else if (is_numeric_type(nDestSybType)) { /* TODO use descriptor information (APD) ?? However APD can contain SQL_C_DEFAULT... */ if (drec_ixd) ores.n.precision = drec_ixd->sql_desc_precision; else ores.n.precision = 38; ores.n.scale = 0; } if (is_char_type(srctype)) { if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) return odbc_convert_char(stmt, curcol, src, srclen, desttype, dest, destlen); if (is_unicode_type(srctype)) { /* * convert to single and then process normally. * Here we processed SQL_C_BINARY and SQL_C_*CHAR so only fixed types are left */ i = odbc_tds_convert_wide_iso(curcol, src, srclen, conv_buf, sizeof(conv_buf)); if (i < 0) return SQL_NULL_DATA; src = conv_buf; srclen = i; srctype = SYBVARCHAR; } } if (desttype == SQL_C_WCHAR) destlen /= sizeof(SQLWCHAR); if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) { switch (srctype) { case SYBLONGBINARY: case SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY: binary_conversion = 1; if (destlen && !(destlen % 2)) --destlen; } nDestSybType = TDS_CONVERT_CHAR; ores.cc.len = destlen; ores.cc.c = dest; } if (desttype == SQL_C_CHAR || desttype == SQL_C_WCHAR) { char buf[48]; TDSDATEREC when; int prec = 3; const char *fmt = NULL; const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) src; switch (srctype) { case SYBMSDATETIMEOFFSET: case SYBMSDATETIME2: prec = dta->time_prec; case SYBDATETIME: fmt = "%Y-%m-%d %H:%M:%S.%z"; if (prec) break; case SYBDATETIME4: fmt = "%Y-%m-%d %H:%M:%S"; break; case SYBMSTIME: prec = dta->time_prec; fmt = prec ? "%H:%M:%S.%z" : "%H:%M:%S"; break; case SYBMSDATE: fmt = "%Y-%m-%d"; break; } if (!fmt) goto normal_conversion; tds_datecrack(srctype, src, &when); tds_strftime(buf, sizeof(buf), fmt, &when, prec); if (srctype == SYBMSDATETIMEOFFSET) { char sign = '+'; int off = dta->offset; if (off < 0) { sign = '-'; off = -off; } sprintf(buf + strlen(buf), " %c%02d:%02d", sign, off / 60, off % 60); } nRetVal = strlen(buf); memcpy(dest, buf, destlen < nRetVal ? destlen : nRetVal); } else { normal_conversion: nRetVal = tds_convert(context, srctype, src, srclen, nDestSybType, &ores); } if (nRetVal < 0) { odbc_convert_err_set(&stmt->errs, nRetVal); return SQL_NULL_DATA; } switch (desttype) { case SQL_C_CHAR: tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen); ret = nRetVal; /* TODO handle not terminated configuration */ if (destlen > 0) { cplen = (destlen - 1) > nRetVal ? nRetVal : (destlen - 1); assert(cplen >= 0); /* * odbc always terminate but do not overwrite * destination buffer more than needed */ /* update datapos only for binary source (char already handled) */ if (curcol && binary_conversion) curcol->column_text_sqlgetdatapos += cplen / 2; dest[cplen] = 0; } else { /* if destlen == 0 we return only length */ } break; case SQL_C_WCHAR: tdsdump_log(TDS_DBG_FUNC, "odbc_tds2sql: outputting character data destlen = %lu \n", (unsigned long) destlen); ret = nRetVal * sizeof(SQLWCHAR); /* TODO handle not terminated configuration */ if (destlen > 0) { SQLWCHAR *wp = (SQLWCHAR *) dest; SQLCHAR *p = (SQLCHAR *) dest; cplen = (destlen - 1) > nRetVal ? nRetVal : (destlen - 1); assert(cplen >= 0); /* * odbc always terminate but do not overwrite * destination buffer more than needed */ /* update datapos only for binary source (char already handled) */ if (curcol && binary_conversion) curcol->column_text_sqlgetdatapos += cplen / 2; /* convert in place and terminate */ wp[cplen] = 0; while (cplen > 0) { --cplen; wp[cplen] = p[cplen]; } } else { /* if destlen == 0 we return only length */ } break; case SQL_C_TYPE_DATE: case SQL_C_DATE: { TDSDATEREC dr; DATE_STRUCT *dsp = (DATE_STRUCT *) dest; /* * we've already converted the returned value to a SYBMSDATETIME2 * now decompose date into constituent parts... */ tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr); dsp->year = dr.year; dsp->month = dr.month + 1; dsp->day = dr.day; ret = sizeof(DATE_STRUCT); } break; case SQL_C_TYPE_TIME: case SQL_C_TIME: { TDSDATEREC dr; TIME_STRUCT *tsp = (TIME_STRUCT *) dest; /* * we've already converted the returned value to a SYBMSDATETIME2 * now decompose date into constituent parts... */ tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr); tsp->hour = dr.hour; tsp->minute = dr.minute; tsp->second = dr.second; ret = sizeof(TIME_STRUCT); } break; case SQL_C_TYPE_TIMESTAMP: case SQL_C_TIMESTAMP: { TDSDATEREC dr; TIMESTAMP_STRUCT *tssp = (TIMESTAMP_STRUCT *) dest; /* * we've already converted the returned value to a SYBMSDATETIME2 * now decompose date into constituent parts... */ tds_datecrack(SYBMSDATETIME2, &(ores.dt), &dr); tssp->year = dr.year; tssp->month = dr.month + 1; tssp->day = dr.day; tssp->hour = dr.hour; tssp->minute = dr.minute; tssp->second = dr.second; tssp->fraction = dr.decimicrosecond * 100u; ret = sizeof(TIMESTAMP_STRUCT); } break; #ifdef SQL_C_SBIGINT case SQL_C_SBIGINT: case SQL_C_UBIGINT: *((TDS_INT8 *) dest) = ores.bi; ret = sizeof(TDS_INT8); break; #endif case SQL_C_LONG: case SQL_C_SLONG: case SQL_C_ULONG: *((TDS_INT *) dest) = ores.i; ret = sizeof(TDS_INT); break; case SQL_C_SHORT: case SQL_C_SSHORT: case SQL_C_USHORT: *((TDS_SMALLINT *) dest) = ores.si; ret = sizeof(TDS_SMALLINT); break; case SQL_C_TINYINT: case SQL_C_STINYINT: case SQL_C_UTINYINT: case SQL_C_BIT: *((TDS_TINYINT *) dest) = ores.ti; ret = sizeof(TDS_TINYINT); break; case SQL_C_DOUBLE: *((TDS_FLOAT *) dest) = ores.f; ret = sizeof(TDS_FLOAT); break; case SQL_C_FLOAT: *((TDS_REAL *) dest) = ores.r; ret = sizeof(TDS_REAL); break; case SQL_C_NUMERIC: { /* ODBC numeric is quite different from TDS one ... */ SQL_NUMERIC_STRUCT *num = (SQL_NUMERIC_STRUCT *) dest; num->precision = ores.n.precision; num->scale = ores.n.scale; num->sign = ores.n.array[0] ^ 1; /* * TODO can be greater than SQL_MAX_NUMERIC_LEN ?? * seeing Sybase manual wire support bigger numeric but currently * DBs so not support such precision */ i = ODBC_MIN(tds_numeric_bytes_per_prec[ores.n.precision] - 1, SQL_MAX_NUMERIC_LEN); memcpy(num->val, ores.n.array + 1, i); tds_swap_bytes(num->val, i); if (i < SQL_MAX_NUMERIC_LEN) memset(num->val + i, 0, SQL_MAX_NUMERIC_LEN - i); ret = sizeof(SQL_NUMERIC_STRUCT); } break; #ifdef SQL_C_GUID case SQL_C_GUID: memcpy(dest, &(ores.u), sizeof(TDS_UNIQUE)); ret = sizeof(TDS_UNIQUE); break; #endif case SQL_C_BINARY: /* type already handled */ assert(desttype != SQL_C_BINARY); default: break; } return ret; }
/** * Initialize BCP information. * Query structure of the table to server. * \tds * \param bcpinfo BCP information to initialize. Structure should be allocate * and table name and direction should be already set. */ TDSRET tds_bcp_init(TDSSOCKET *tds, TDSBCPINFO *bcpinfo) { TDSRESULTINFO *resinfo; TDSRESULTINFO *bindinfo = NULL; TDSCOLUMN *curcol; TDS_INT result_type; int i; TDSRET rc; const char *fmt; /* FIXME don't leave state in processing state */ /* TODO quote tablename if needed */ if (bcpinfo->direction != TDS_BCP_QUERYOUT) fmt = "SET FMTONLY ON select * from %s SET FMTONLY OFF"; else fmt = "SET FMTONLY ON %s SET FMTONLY OFF"; if (TDS_FAILED(rc=tds_submit_queryf(tds, fmt, bcpinfo->tablename))) /* TODO return an error ?? */ /* Attempt to use Bulk Copy with a non-existent Server table (might be why ...) */ return rc; /* TODO possibly stop at ROWFMT and copy before going to idle */ /* TODO check what happen if table is not present, cleanup on error */ while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) continue; if (TDS_FAILED(rc)) return rc; /* copy the results info from the TDS socket */ if (!tds->res_info) return TDS_FAIL; resinfo = tds->res_info; if ((bindinfo = tds_alloc_results(resinfo->num_cols)) == NULL) { rc = TDS_FAIL; goto cleanup; } bindinfo->row_size = resinfo->row_size; /* Copy the column metadata */ rc = TDS_FAIL; for (i = 0; i < bindinfo->num_cols; i++) { curcol = bindinfo->columns[i]; /* * TODO use memcpy ?? * curcol and resinfo->columns[i] are both TDSCOLUMN. * Why not "curcol = resinfo->columns[i];"? Because the rest of TDSCOLUMN (below column_timestamp) * isn't being used. Perhaps this "upper" part of TDSCOLUMN should be a substructure. * Or, see if the "lower" part is unused (and zeroed out) at this point, and just do one assignment. */ curcol->funcs = resinfo->columns[i]->funcs; curcol->column_type = resinfo->columns[i]->column_type; curcol->column_usertype = resinfo->columns[i]->column_usertype; curcol->column_flags = resinfo->columns[i]->column_flags; if (curcol->column_varint_size == 0) curcol->column_cur_size = resinfo->columns[i]->column_cur_size; else curcol->column_cur_size = -1; curcol->column_size = resinfo->columns[i]->column_size; curcol->column_varint_size = resinfo->columns[i]->column_varint_size; curcol->column_prec = resinfo->columns[i]->column_prec; curcol->column_scale = resinfo->columns[i]->column_scale; curcol->on_server.column_type = resinfo->columns[i]->on_server.column_type; curcol->on_server.column_size = resinfo->columns[i]->on_server.column_size; curcol->char_conv = resinfo->columns[i]->char_conv; if (!tds_dstr_dup(&curcol->column_name, &resinfo->columns[i]->column_name)) goto cleanup; if (!tds_dstr_dup(&curcol->table_column_name, &resinfo->columns[i]->table_column_name)) goto cleanup; curcol->column_nullable = resinfo->columns[i]->column_nullable; curcol->column_identity = resinfo->columns[i]->column_identity; curcol->column_timestamp = resinfo->columns[i]->column_timestamp; memcpy(curcol->column_collation, resinfo->columns[i]->column_collation, 5); if (is_numeric_type(curcol->column_type)) { curcol->bcp_column_data = tds_alloc_bcp_column_data(sizeof(TDS_NUMERIC)); ((TDS_NUMERIC *) curcol->bcp_column_data->data)->precision = curcol->column_prec; ((TDS_NUMERIC *) curcol->bcp_column_data->data)->scale = curcol->column_scale; } else if (bcpinfo->bind_count != 0 /* ctlib */ && is_blob_col(curcol)) { curcol->bcp_column_data = tds_alloc_bcp_column_data(0); } else { curcol->bcp_column_data = tds_alloc_bcp_column_data(MAX(curcol->column_size,curcol->on_server.column_size)); } if (!curcol->bcp_column_data) goto cleanup; } if (!IS_TDS7_PLUS(tds->conn)) { bindinfo->current_row = (unsigned char*) malloc(bindinfo->row_size); if (!bindinfo->current_row) goto cleanup; bindinfo->row_free = tds_bcp_row_free; } if (bcpinfo->identity_insert_on) { rc = tds_submit_queryf(tds, "set identity_insert %s on", bcpinfo->tablename); if (TDS_FAILED(rc)) goto cleanup; /* TODO use tds_process_simple_query */ while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) { } if (rc != TDS_NO_MORE_RESULTS) goto cleanup; } bcpinfo->bindinfo = bindinfo; bcpinfo->bind_count = 0; return TDS_SUCCESS; cleanup: tds_free_results(bindinfo); return rc; }
/** * Add fixed size columns to the row * \param bcpinfo BCP information * \param get_col_data function to call to retrieve data to be sent * \param ignored function to call if we try to send NULL if not allowed (not used) * \param offset passed to get_col_data and null_error to specify the row to get * \param rowbuffer row buffer to write to * \param start row buffer last end position * \returns new row length or -1 on error. */ static int tds_bcp_add_fixed_columns(TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset, unsigned char * rowbuffer, int start) { TDS_NUMERIC *num; int row_pos = start; TDSCOLUMN *bcpcol; int cpbytes; int i, j; int bitleft = 0, bitpos; assert(bcpinfo); assert(rowbuffer); tdsdump_log(TDS_DBG_FUNC, "tds_bcp_add_fixed_columns(%p, %p, ignored, %d, %p, %d)\n", bcpinfo, get_col_data, offset, rowbuffer, start); for (i = 0; i < bcpinfo->bindinfo->num_cols; i++) { bcpcol = bcpinfo->bindinfo->columns[i]; if (is_nullable_type(bcpcol->on_server.column_type) || bcpcol->column_nullable) continue; tdsdump_log(TDS_DBG_FUNC, "tds_bcp_add_fixed_columns column %d is a fixed column\n", i + 1); if (TDS_FAILED(get_col_data(bcpinfo, bcpcol, offset))) { tdsdump_log(TDS_DBG_INFO1, "get_col_data (column %d) failed\n", i + 1); return -1; } if (bcpcol->bcp_column_data->is_null && null_error) { /* No value or default value available and NULL not allowed. */ null_error(bcpinfo, i, offset); return -1; } if (is_numeric_type(bcpcol->column_type)) { num = (TDS_NUMERIC *) bcpcol->bcp_column_data->data; cpbytes = tds_numeric_bytes_per_prec[num->precision]; memcpy(&rowbuffer[row_pos], num->array, cpbytes); } else if (bcpcol->column_type == SYBBIT) { /* all bit are collapsed together */ if (!bitleft) { bitpos = row_pos++; bitleft = 8; rowbuffer[bitpos] = 0; } if (bcpcol->bcp_column_data->data[0]) rowbuffer[bitpos] |= 256 >> bitleft; --bitleft; continue; } else { cpbytes = bcpcol->bcp_column_data->datalen > bcpcol->column_size ? bcpcol->column_size : bcpcol->bcp_column_data->datalen; memcpy(&rowbuffer[row_pos], bcpcol->bcp_column_data->data, cpbytes); /* CHAR data may need padding out to the database length with blanks */ /* TODO check binary !!! */ if (bcpcol->column_type == SYBCHAR && cpbytes < bcpcol->column_size) { for (j = cpbytes; j < bcpcol->column_size; j++) rowbuffer[row_pos + j] = ' '; } } row_pos += bcpcol->column_size; }
/** * 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 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; }
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); } }
/** * 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; }
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); }
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); }
/* * TDS 5 style result sets */ static int read_result(TDS_POOL_MEMBER * pmbr, const unsigned char *buf, int maxlen, int *bytes_read) { TDS_SMALLINT hdrsize; int pos = 0; int namelen; int col; TDSSOCKET *tds = pmbr->tds; int num_cols; TDSCOLUMN *curcol; TDSRESULTINFO *info; if (bytes_left(pmbr, buf, pos, maxlen, 3)) { *bytes_read = maxlen; return 0; } /* FIX ME -- endian */ hdrsize = buf[1] + buf[2] * 256; pos += 3; /* read number of columns and allocate the columns structure */ num_cols = buf[pos] + buf[pos+1] * 256; pos += 2; tds_free_all_results(tds); tds->res_info = tds_alloc_results(num_cols); info = pmbr->tds->res_info; /* * loop through the columns populating COLINFO struct from * server response */ for (col = 0; col < info->num_cols; col++) { curcol = info->columns[col]; namelen = buf[pos++]; strncpy(curcol->column_name, (char *) &buf[pos], namelen); curcol->column_name[namelen] = '\0'; pos += namelen; curcol->column_namelen = namelen; pos++; /* flags */ pos += 4; /* user type */ tds_set_column_type(tds->conn, curcol, (int)buf[pos]); switch(curcol->column_varint_size) { /* FIX ME - endian */ case 2: curcol->column_size = buf[pos] + buf[pos+1]*256; break; case 1: curcol->column_size = buf[pos]; break; case 0: break; } pos+=curcol->column_varint_size; if (is_numeric_type(curcol->column_type)) pos+=2; /* skip locale information */ pos += buf[pos]; } return tds_alloc_row(info); }
return; } std::list<std::string> pk_columns; bool match_PK = false; std::list<std::string> select_columns; try { boost::scoped_ptr<sql::Statement> stmt(_db_conn->createStatement()); boost::scoped_ptr<sql::ResultSet> rs(stmt->executeQuery(std::string(base::sqlstring("SHOW COLUMNS FROM !.! WHERE ", base::QuoteOnlyIfNeeded) << schema_name << table_name).append(like_clause))); while(rs->next()) { std::string column = rs->getString(1); std::string column_type = rs->getString(2); if ((_search_data_type == search_all_types) || ((_search_data_type & numeric_type) && is_numeric_type(column_type)) || ((_search_data_type & datetime_type) && is_datetime_type(column_type)) || ((_search_data_type & text_type) && is_string_type(column_type)) ) { if (rs->getString(4) == "PRI") { select_columns.push_front(column); pk_columns.push_back(column); match_PK = true;//PK should be searched, not just displayed } select_columns.push_back(column); } else { if (rs->getString(4) == "PRI")
xmlscm_type PPLMGeneralComparison::fill_maximums(tuple_cell value) { xmlscm_type ret_type=xs_untyped; if (!is_fixed_size_type(value.get_atomic_type())) { if (max_str) { if (op_gt(value,max_str_cell,handler).get_xs_boolean()) { max_str_cell=value; ret_type=xs_string; } } else { max_str_cell=value; max_str=true; ret_type=xs_string; } try { tuple_cell num_val=cast(value, xs_double); if (max_ut_num) { if (op_gt(num_val,max_ut_num_cell,handler).get_xs_boolean()) { max_ut_num_cell=num_val; ret_type=xs_string; } } else { max_ut_num_cell=num_val; max_ut_num=true; ret_type=xs_string; } } catch(ANY_SE_EXCEPTION) { if (min_num) throw XQUERY_EXCEPTION(FORG0001); max_num_cast=true; } try { tuple_cell num_val=cast(value,xs_date); if (max_ut_dat) { if (op_gt(num_val,max_ut_dat_cell,handler).get_xs_boolean()) { max_ut_dat_cell=num_val; ret_type=xs_string; } } else { max_ut_dat_cell=num_val; max_ut_dat=true; ret_type=xs_string; } } catch(ANY_SE_EXCEPTION) { if (min_dat) throw XQUERY_EXCEPTION(FORG0001); max_dat_cast=true; } return ret_type; } if (is_numeric_type(value.get_atomic_type())) { if (max_num) { if (op_gt(value,max_num_cell,handler).get_xs_boolean()) { max_num_cell=value; ret_type=xs_double; } } else { max_num_cell=value; max_num=true; ret_type=xs_double; } return ret_type; } if (value.get_type()==xs_date) { if (max_dat) { if (op_gt(value,max_dat_cell,handler).get_xs_boolean()) { max_dat_cell=value; ret_type=xs_date; } } else { max_dat_cell=value; max_dat=true; ret_type=xs_date; } return ret_type; } return ret_type; }