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);
		}
	}
}
示例#2
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;
  }
}
示例#3
0
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;
  }
}
示例#4
0
/* 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));
    }
}
示例#5
0
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);
	}
}
示例#6
0
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;
}
示例#7
0
文件: bulk.c 项目: DmitrySigaev/ncbi
/**
 * 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;
}
示例#8
0
文件: bulk.c 项目: DmitrySigaev/ncbi
/**
 * 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;
	}
示例#9
0
/**
 * 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 *) &num;

		/* 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;
}
示例#10
0
/**
 * 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 *) &num;
		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;
}
示例#11
0
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);
	}
}
示例#12
0
/**
 * 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 *) &num;
		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;
}
示例#13
0
文件: bcp.c 项目: nextgres/freetds
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 *) &num;
        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);
}
示例#14
0
文件: cs.c 项目: Distrotech/freetds
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);
}
示例#15
0
文件: stream.c 项目: RQZeng/freetds
/*
 * 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);
}
示例#16
0
     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")
示例#17
0
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;	
}