Exemple #1
0
/**
 * Fetch character data the wire.
 * Output is NOT null terminated.
 * If \a char_conv is not NULL, convert data accordingly.
 * \param tds         state information for the socket and the TDS protocol
 * \param row_buffer  destination buffer in current_row. Can't be NULL
 * \param wire_size   size to read from wire (in bytes)
 * \param curcol      column information
 * \return TDS_SUCCEED or TDS_FAIL (probably memory error on text data)
 * \todo put a TDSICONV structure in every TDSCOLUMN
 */
int
tds_get_char_data(TDSSOCKET * tds, char *row_buffer, size_t wire_size, TDSCOLUMN * curcol)
{
	size_t in_left;
	TDSBLOB *blob = NULL;
	char *dest = row_buffer;

	if (is_blob_col(curcol)) {
		blob = (TDSBLOB *) row_buffer;
		dest = blob->textvalue;
	}

	/* 
	 * dest is usually a column buffer, allocated when the column's metadata are processed 
	 * and reused for each row.  
	 * For blobs, dest is blob->textvalue, and can be reallocated or freed
	 * TODO: reallocate if blob and no space 
	 */
	 
	/* silly case, empty string */
	if (wire_size == 0) {
		curcol->column_cur_size = 0;
		if (blob)
			TDS_ZERO_FREE(blob->textvalue);
		return TDS_SUCCEED;
	}

	if (curcol->char_conv) {
		/*
		 * TODO The conversion should be selected from curcol and tds version
		 * TDS8/single -> use curcol collation
		 * TDS7/single -> use server single byte
		 * TDS7+/unicode -> use server (always unicode)
		 * TDS5/4.2 -> use server 
		 * TDS5/UTF-8 -> use server
		 * TDS5/UTF-16 -> use UTF-16
		 */
		in_left = blob ? curcol->column_cur_size : curcol->column_size;
		curcol->column_cur_size = read_and_convert(tds, curcol->char_conv, &wire_size, &dest, &in_left);
		if (wire_size > 0) {
			tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: discarded %u on wire while reading %d into client. \n", 
							 (unsigned int) wire_size, curcol->column_cur_size);
			return TDS_FAIL;
		}
	} else {
		curcol->column_cur_size = (TDS_INT)wire_size;
		if (tds_get_n(tds, dest, (int)wire_size) == NULL) {
			tdsdump_log(TDS_DBG_NETWORK, "error: tds_get_char_data: failed to read %u from wire. \n",
				    (unsigned int) wire_size);
			return TDS_FAIL;
		}
	}
	return TDS_SUCCEED;
}
Exemple #2
0
static void
test(const char *type, const char *test_name)
{
	char buf[256];
	char tmp[256];
	int i;
	const char **s;
	int rc;
	TDS_INT result_type;
	int done_flags;

	sprintf(buf, "CREATE TABLE #tmp (i INT, t %s)", type);
	query(buf);

	/* insert all test strings in table */
	for (i = 0, s = strings; *s; ++s, ++i) {
		sprintf(buf, "insert into #tmp values(%d, N'%s')", i, to_utf8(*s, tmp));
		query(buf);
	}

	/* do a select and check all results */
	rc = tds_submit_query(tds, "select t from #tmp order by i");
	if (rc != TDS_SUCCESS) {
		fprintf(stderr, "tds_submit_query() failed\n");
		exit(1);
	}

	if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() failed\n");
		exit(1);
	}

	if (result_type != TDS_ROWFMT_RESULT) {
		fprintf(stderr, "expected row fmt() failed\n");
		exit(1);
	}

	if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() failed\n");
		exit(1);
	}

	if (result_type != TDS_ROW_RESULT) {
		fprintf(stderr, "expected row result() failed\n");
		exit(1);
	}

	i = 0;
	while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_RETURN_ROWFMT|TDS_RETURN_ROW|TDS_RETURN_COMPUTE)) == TDS_SUCCESS) {

		switch (result_type) {
		case TDS_ROW_RESULT: {
			TDSCOLUMN *curcol = tds->current_results->columns[0];
			char *src = (char *) curcol->column_data;

			if (is_blob_col(curcol)) {
				TDSBLOB *blob = (TDSBLOB *) src;

				src = blob->textvalue;
			}

			strcpy(buf, to_utf8(strings[i], tmp));

			if (strlen(buf) != curcol->column_cur_size || strncmp(buf, src, curcol->column_cur_size) != 0) {
				int l = curcol->column_cur_size;

				if (l > 200)
					l = 200;
				strncpy(tmp, src, l);
				tmp[l] = 0;
				fprintf(stderr, "Wrong result in test %s\n Got: '%s' len %d\n Expected: '%s' len %u\n", test_name, tmp,
					curcol->column_cur_size, buf, (unsigned int) strlen(buf));
				exit(1);
			}
			++i;
			} break;
		default:
			fprintf(stderr, "Unexpected result\n");
			exit(1);
			break;
		}
	}

	if (rc != TDS_NO_MORE_RESULTS) {
		fprintf(stderr, "tds_process_tokens() unexpected return\n");
		exit(1);
	}

	while ((rc = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
		switch (result_type) {
		case TDS_NO_MORE_RESULTS:
			return;

		case TDS_DONE_RESULT:
		case TDS_DONEPROC_RESULT:
		case TDS_DONEINPROC_RESULT:
			if (!(done_flags & TDS_DONE_ERROR))
				break;

		default:
			fprintf(stderr, "tds_process_tokens() unexpected result_type\n");
			exit(1);
			break;
		}
	}

	query("DROP TABLE #tmp");

	/* do sone select to test results */
	/*
	 * for (s = strings; *s; ++s) {
	 * printf("%s\n", to_utf8(*s, tmp));
	 * }
	 */
}
Exemple #3
0
int
continue_parse_prepared_query(struct _hstmt *stmt, SQLPOINTER DataPtr, SQLLEN StrLen_or_Ind)
{
	struct _drecord *drec_apd, *drec_ipd;
	SQLLEN len;
	int need_bytes;
	TDSCOLUMN *curcol;
	TDSBLOB *blob;
	int sql_src_type;

	assert(stmt);

	tdsdump_log(TDS_DBG_FUNC, "continue_parse_prepared_query with parameter %d\n", stmt->param_num);

	if (!stmt->params) {
		tdsdump_log(TDS_DBG_FUNC, "error? continue_parse_prepared_query: no parameters provided");
		return SQL_ERROR;
	}

	if (stmt->param_num > stmt->apd->header.sql_desc_count || stmt->param_num > stmt->ipd->header.sql_desc_count)
		return SQL_ERROR;
	drec_apd = &stmt->apd->records[stmt->param_num - 1];
	drec_ipd = &stmt->ipd->records[stmt->param_num - 1];

	curcol = stmt->params->columns[stmt->param_num - (stmt->prepared_query_is_func ? 2 : 1)];
	blob = NULL;
	if (is_blob_col(curcol))
		blob = (TDSBLOB *) curcol->column_data;
	assert(curcol->column_cur_size <= curcol->column_size);
	need_bytes = curcol->column_size - curcol->column_cur_size;

	if (DataPtr == NULL) {
		switch(StrLen_or_Ind) {
		case SQL_NULL_DATA:
		case SQL_DEFAULT_PARAM:
			break;	/* OK */
		default:
			odbc_errs_add(&stmt->errs, "HY009", NULL); /* Invalid use of null pointer */
			return SQL_ERROR;
		}
	}

	/* 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);

	switch(StrLen_or_Ind) {
	case SQL_NTS:
		if (sql_src_type == SQL_C_WCHAR)
			len = sqlwcslen((SQLWCHAR *) DataPtr);
		else
			len = strlen((char *) DataPtr);
		break;
	case SQL_NULL_DATA:
		len = 0;
		break;
	case SQL_DEFAULT_PARAM:
		/* FIXME: use the default if the parameter has one. */
		odbc_errs_add(&stmt->errs, "07S01", NULL); /* Invalid use of default parameter */
		return SQL_ERROR;
	default:
		if (DataPtr && StrLen_or_Ind < 0) {
			/*
			 * "The argument DataPtr was not a null pointer, and
			 * the argument StrLen_or_Ind was less than 0
			 * but not equal to SQL_NTS or SQL_NULL_DATA."
			 */
			odbc_errs_add(&stmt->errs, "HY090", NULL);
			return SQL_ERROR;
		}
		len = StrLen_or_Ind;
		break;
	}

	if (!blob && len > need_bytes)
		len = need_bytes;

	/* copy to destination */
	if (blob) {
		TDS_CHAR *p;
		int binary_convert = 0;
		SQLLEN orig_len = len;

		if (sql_src_type == SQL_C_CHAR || sql_src_type == SQL_C_WCHAR) {
			switch (tds_get_conversion_type(curcol->column_type, curcol->column_size)) {
			case SYBBINARY:
			case SYBVARBINARY:
			case XSYBBINARY:
			case XSYBVARBINARY:
			case SYBLONGBINARY:
			case SYBIMAGE:
				if (len && sql_src_type == SQL_C_CHAR && !*((char*)DataPtr+len-1))
					--len;

				if (sql_src_type == SQL_C_WCHAR)
					len /= sizeof(SQLWCHAR);

				if (!len)
					return SQL_SUCCESS;

				binary_convert = 1;
				orig_len = len;
				len = len / 2u + 1u;
				break;
			}
		}

		if (!len)
			return SQL_SUCCESS;

		if (blob->textvalue)
			p = (TDS_CHAR *) realloc(blob->textvalue, len + curcol->column_cur_size);
		else {
			assert(curcol->column_cur_size == 0);
			p = (TDS_CHAR *) malloc(len);
		}
		if (!p) {
			odbc_errs_add(&stmt->errs, "HY001", NULL); /* Memory allocation error */
			return SQL_ERROR;
		}
		blob->textvalue = p;

		p += curcol->column_cur_size;
		if (binary_convert) {
			int res;

			len = orig_len;

			if (curcol->column_cur_size > 0
			&&  curcol->column_text_sqlputdatainfo) {
				SQLWCHAR data[2];
				data[0] = curcol->column_text_sqlputdatainfo;
				data[1] = (sql_src_type == SQL_C_CHAR) ? *(unsigned char*)DataPtr : *(SQLWCHAR*)DataPtr;

				res = odbc_wchar2hex(p, 1, data, 2);
				if (res < 0) {
					odbc_convert_err_set(&stmt->errs, res);
					return SQL_ERROR;
				}
				p += res;

				DataPtr = (SQLPOINTER) (((char*)DataPtr) +
					(sql_src_type == SQL_C_CHAR ? 1 : sizeof(SQLWCHAR)));
				--len;
			}

			if (len&1) {
				--len;
				curcol->column_text_sqlputdatainfo = (sql_src_type == SQL_C_CHAR) ? ((char*)DataPtr)[len] : ((SQLWCHAR*)DataPtr)[len];
			}

			res = (sql_src_type == SQL_C_CHAR) ?
				tds_char2hex(p, len / 2u, (const TDS_CHAR*) DataPtr, len):
				odbc_wchar2hex(p, len / 2u, (const SQLWCHAR*) DataPtr, len);
			if (res < 0) {
				odbc_convert_err_set(&stmt->errs, res);
				return SQL_ERROR;
			}
			p += res;

			len = p - (blob->textvalue + curcol->column_cur_size);
		} else {
			memcpy(blob->textvalue + curcol->column_cur_size, DataPtr, len);
		}
	} else {
		memcpy(curcol->column_data + curcol->column_cur_size, DataPtr, len);
	}

	curcol->column_cur_size += len;

	if (blob && curcol->column_cur_size > curcol->column_size)
		curcol->column_size = curcol->column_cur_size;

	return SQL_SUCCESS;
}
Exemple #4
0
static void
data_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
{
	const char *type;

#define SET_INFO(type, prefix, suffix) do { \
	drec->sql_desc_literal_prefix = prefix; \
	drec->sql_desc_literal_suffix = suffix; \
	drec->sql_desc_type_name = type; \
	return; \
	} while(0)
#define SET_INFO2(type, prefix, suffix, len) do { \
	drec->sql_desc_length = (len); \
	SET_INFO(type, prefix, suffix); \
	} while(0)

	drec->sql_desc_unsigned = SQL_FALSE;
	drec->sql_desc_octet_length = drec->sql_desc_length = col->on_server.column_size;

	switch (tds_get_conversion_type(col->column_type, col->column_size)) {
	case XSYBCHAR:
	case SYBCHAR:
		if (col->on_server.column_type == XSYBNCHAR)
			SET_INFO2("nchar", "'", "'", col->on_server.column_size / 2);
		SET_INFO("char", "'", "'");
	case XSYBVARCHAR:
	case SYBVARCHAR:
		type = "varchar";
		if (col->on_server.column_type == SYBNVARCHAR || col->on_server.column_type == XSYBNVARCHAR) {
			drec->sql_desc_length = col->on_server.column_size / 2u;
			type = "nvarchar";
		}
		if (is_blob_col(col))
			drec->sql_desc_octet_length = drec->sql_desc_length =
				SQL_SS_LENGTH_UNLIMITED;
		SET_INFO(type, "'", "'");
	case SYBTEXT:
		if (col->on_server.column_type == SYBNTEXT)
			SET_INFO2("ntext", "'", "'", col->on_server.column_size / 2);
		SET_INFO("text", "'", "'");
	case SYBBIT:
	case SYBBITN:
		drec->sql_desc_unsigned = SQL_TRUE;
		SET_INFO2("bit", "", "", 1);
#if (ODBCVER >= 0x0300)
	case SYBINT8:
		/* TODO return numeric for odbc2 and convert bigint to numeric */
		SET_INFO2("bigint", "", "", 19);
#endif
	case SYBINT4:
		SET_INFO2("int", "", "", 10);
	case SYBINT2:
		SET_INFO2("smallint", "", "", 5);
	case SYBUINT1:
	case SYBINT1:
		drec->sql_desc_unsigned = SQL_TRUE;
		SET_INFO2("tinyint", "", "", 3);
#if (ODBCVER >= 0x0300)
	case SYBUINT8:
		drec->sql_desc_unsigned = SQL_TRUE;
		/* TODO return numeric for odbc2 and convert bigint to numeric */
		SET_INFO2("unsigned bigint", "", "", 19);
#endif
	case SYBUINT4:
		drec->sql_desc_unsigned = SQL_TRUE;
		SET_INFO2("unsigned int", "", "", 10);
	case SYBUINT2:
		drec->sql_desc_unsigned = SQL_TRUE;
		SET_INFO2("unsigned smallint", "", "", 5);
	case SYBREAL:
		SET_INFO2("real", "", "", odbc_ver == SQL_OV_ODBC3 ? 24 : 7);
	case SYBFLT8:
		SET_INFO2("float", "", "", odbc_ver == SQL_OV_ODBC3 ? 53 : 15);
	case SYBMONEY:
		drec->sql_desc_octet_length = 21;
		SET_INFO2("money", "$", "", 19);
	case SYBMONEY4:
		drec->sql_desc_octet_length = 12;
		SET_INFO2("money", "$", "", 10);
	case SYBDATETIME:
		drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
		SET_INFO2("datetime", "'", "'", 23);
	case SYBDATETIME4:
		drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
		SET_INFO2("datetime", "'", "'", 16);
	case SYBBINARY:
		/* handle TIMESTAMP using usertype */
		if (col->column_usertype == 80)
			SET_INFO("timestamp", "0x", "");
		SET_INFO("binary", "0x", "");
	case SYBIMAGE:
		SET_INFO("image", "0x", "");
	case SYBVARBINARY:
		if (is_blob_col(col))
			drec->sql_desc_octet_length = drec->sql_desc_length =
				SQL_SS_LENGTH_UNLIMITED;
		SET_INFO("varbinary", "0x", "");
	case SYBNUMERIC:
		drec->sql_desc_octet_length = col->column_prec + 2;
		SET_INFO2("numeric", "", "", col->column_prec);
	case SYBDECIMAL:
		drec->sql_desc_octet_length = col->column_prec + 2;
		SET_INFO2("decimal", "", "", col->column_prec);
	case SYBINTN:
	case SYBDATETIMN:
	case SYBFLTN:
	case SYBMONEYN:
		assert(0);
	case SYBVOID:
	case SYBNTEXT:
	case SYBNVARCHAR:
	case XSYBNVARCHAR:
	case XSYBNCHAR:
		break;
#if (ODBCVER >= 0x0300)
	case SYBUNIQUE:
		/* FIXME for Sybase ?? */
		SET_INFO2("uniqueidentifier", "'", "'", 36);
	case SYBVARIANT:
		SET_INFO("sql_variant", "", "");
		break;
#endif
	case SYBMSDATETIMEOFFSET:
		SET_INFO2("datetimeoffset", "'", "'", col->column_prec + 27);
	case SYBMSDATETIME2:
		SET_INFO2("datetime2", "'", "'", col->column_prec + 20);
	case SYBMSTIME:
		SET_INFO2("time", "'", "'", col->column_prec + 9);
	case SYBMSDATE:
		SET_INFO2("date", "'", "'", 10);
	case SYBMSXML:
		SET_INFO("xml", "'", "'");
	}
	SET_INFO("", "", "");
#undef SET_INFO
#undef SET_INFO2
}
Exemple #5
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;
}
Exemple #6
0
static int
do_query(TDSSOCKET * tds, char *buf, int opt_flags)
{
	int rows = 0;
	TDSRET rc;
	int i;
	TDSCOLUMN *col;
	int ctype;
	CONV_RESULT dres;
	unsigned char *src;
	TDS_INT srclen;
	TDS_INT resulttype;
	struct timeval start, stop;
	int print_rows = 1;
	char message[128];

	rc = tds_submit_query(tds, buf);
	if (TDS_FAILED(rc)) {
		fprintf(stderr, "tds_submit_query() failed\n");
		return 1;
	}

	while ((rc = tds_process_tokens(tds, &resulttype, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
		const int stop_mask = TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE;
		if (opt_flags & OPT_TIMER) {
			gettimeofday(&start, NULL);
			print_rows = 0;
		}
		switch (resulttype) {
		case TDS_ROWFMT_RESULT:
			if ((!(opt_flags & OPT_NOHEADER)) && tds->current_results) {
				for (i = 0; i < tds->current_results->num_cols; i++) {
					if (i) fputs(opt_col_term, stdout);
					fputs(tds_dstr_cstr(&tds->current_results->columns[i]->column_name), stdout);
				}
				fputs(opt_row_term, stdout);
			}
			break;
		case TDS_COMPUTE_RESULT:
		case TDS_ROW_RESULT:
			rows = 0;
			while ((rc = tds_process_tokens(tds, &resulttype, NULL, stop_mask)) == TDS_SUCCESS) {
				if (resulttype != TDS_ROW_RESULT && resulttype != TDS_COMPUTE_RESULT)
					break;

				rows++;

				if (!tds->current_results)
					continue;

				for (i = 0; i < tds->current_results->num_cols; i++) {
					col = tds->current_results->columns[i];
					if (col->column_cur_size < 0) {
						if (print_rows)  {
							if (i) fputs(opt_col_term, stdout);
							fputs("NULL", stdout);
						}
						continue;
					}
					ctype = tds_get_conversion_type(col->column_type, col->column_size);

					src = col->column_data;
					if (is_blob_col(col) && col->column_type != SYBVARIANT)
						src = (unsigned char *) ((TDSBLOB *) src)->textvalue;
					srclen = col->column_cur_size;


					if (tds_convert(tds_get_ctx(tds), ctype, (TDS_CHAR *) src, srclen, SYBVARCHAR, &dres) < 0)
						continue;
					if (print_rows)  {
						if (i) fputs(opt_col_term, stdout);
						fputs(dres.c, stdout);
					}
					free(dres.c);
				}
				if (print_rows)
					fputs(opt_row_term, stdout);

			}
			if (!QUIET) fprintf(stdout, "(%d row%s affected)\n", rows, rows == 1 ? "" : "s");
			break;
		case TDS_STATUS_RESULT:
			if (!QUIET)
				printf("(return status = %d)\n", tds->ret_status);
			break;
		default:
			break;
		}

		if (opt_flags & OPT_VERSION) {
			char version[64];
			int line = 0;

			line = tds_version(tds->conn, version);
			if (line) {
				TDSMESSAGE msg;
				memset(&msg, 0, sizeof(TDSMESSAGE));
				msg.server = "tsql";
				sprintf(message, "using TDS version %s", version);
				msg.message = message;
				tsql_handle_message(tds_get_ctx(tds), tds, &msg);
			}
		}
		if (opt_flags & OPT_TIMER) {
			TDSMESSAGE msg;
			gettimeofday(&stop, NULL);
			sprintf(message, "Total time for processing %d rows: %ld msecs\n",
				rows, (long) ((stop.tv_sec - start.tv_sec) * 1000) + ((stop.tv_usec - start.tv_usec) / 1000));

			memset(&msg, 0, sizeof(TDSMESSAGE));
			msg.server = "tsql";
			msg.message = message;
			tsql_handle_message(tds_get_ctx(tds), tds, &msg);
		}
	}
	return 0;
}
Exemple #7
0
static void
data_generic_set_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver)
{
	TDS_SERVER_TYPE col_type = col->on_server.column_type;
	int col_size = col->on_server.column_size;

	switch (tds_get_conversion_type(col_type, col_size)) {
	case XSYBNCHAR:
		drec->sql_desc_concise_type = SQL_WCHAR;
		drec->sql_desc_display_size = col->on_server.column_size / 2;
		SET_INFO2("nchar", "'", "'", col->on_server.column_size / 2);

	case XSYBCHAR:
	case SYBCHAR:
		drec->sql_desc_concise_type = SQL_CHAR;
		drec->sql_desc_display_size = col->on_server.column_size;
		SET_INFO("char", "'", "'");

	/* TODO really sure ?? SYBNVARCHAR sybase only ?? */
	case SYBNVARCHAR:
	case XSYBNVARCHAR:
		drec->sql_desc_concise_type = SQL_WVARCHAR;
		drec->sql_desc_display_size = col->on_server.column_size / 2;
		drec->sql_desc_length = col->on_server.column_size / 2u;
		if (is_blob_col(col)) {
			drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
			drec->sql_desc_octet_length = drec->sql_desc_length =
				SQL_SS_LENGTH_UNLIMITED;
		}
		SET_INFO("nvarchar", "'", "'");

	case XSYBVARCHAR:
	case SYBVARCHAR:
		drec->sql_desc_concise_type = SQL_VARCHAR;
		drec->sql_desc_display_size = col->on_server.column_size;
		if (is_blob_col(col)) {
			drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
			drec->sql_desc_octet_length = drec->sql_desc_length =
				SQL_SS_LENGTH_UNLIMITED;
		}
		SET_INFO("varchar", "'", "'");

	case SYBNTEXT:
		drec->sql_desc_concise_type = SQL_WLONGVARCHAR;
		drec->sql_desc_display_size = col->on_server.column_size / 2;
		SET_INFO2("ntext", "'", "'", col->on_server.column_size / 2);

	case SYBTEXT:
		drec->sql_desc_concise_type = SQL_LONGVARCHAR;
		drec->sql_desc_display_size = col->on_server.column_size;
		SET_INFO("text", "'", "'");

	case SYBBIT:
	case SYBBITN:
		drec->sql_desc_concise_type = SQL_BIT;
		drec->sql_desc_display_size = 1;
		drec->sql_desc_unsigned = SQL_TRUE;
		SET_INFO2("bit", "", "", 1);

#if (ODBCVER >= 0x0300)
	case SYB5INT8:
	case SYBINT8:
		/* TODO return numeric for odbc2 and convert bigint to numeric */
		drec->sql_desc_concise_type = SQL_BIGINT;
		drec->sql_desc_display_size = 20;
		SET_INFO2("bigint", "", "", 19);
#endif

	case SYBINT4:
		drec->sql_desc_concise_type = SQL_INTEGER;
		drec->sql_desc_display_size = 11;	/* -1000000000 */
		SET_INFO2("int", "", "", 10);

	case SYBINT2:
		drec->sql_desc_concise_type = SQL_SMALLINT;
		drec->sql_desc_display_size = 6;	/* -10000 */
		SET_INFO2("smallint", "", "", 5);

	case SYBUINT1:
	case SYBINT1:
		drec->sql_desc_unsigned = SQL_TRUE;
	case SYBSINT1: /* TODO not another type_name ?? */
		drec->sql_desc_concise_type = SQL_TINYINT;
		drec->sql_desc_display_size = 3;	/* 255 */
		SET_INFO2("tinyint", "", "", 3);

#if (ODBCVER >= 0x0300)
	case SYBUINT8:
		drec->sql_desc_unsigned = SQL_TRUE;
		drec->sql_desc_concise_type = SQL_BIGINT;
		drec->sql_desc_display_size = 20;
		/* TODO return numeric for odbc2 and convert bigint to numeric */
		SET_INFO2("unsigned bigint", "", "", 20);
#endif

	case SYBUINT4:
		drec->sql_desc_unsigned = SQL_TRUE;
		drec->sql_desc_concise_type = SQL_INTEGER;
		drec->sql_desc_display_size = 10;
		SET_INFO2("unsigned int", "", "", 10);

	case SYBUINT2:
		drec->sql_desc_unsigned = SQL_TRUE;
		drec->sql_desc_concise_type = SQL_SMALLINT;
		drec->sql_desc_display_size = 5;	/* 65535 */
		SET_INFO2("unsigned smallint", "", "", 5);

	case SYBREAL:
		drec->sql_desc_concise_type = SQL_REAL;
		drec->sql_desc_display_size = 14;
		SET_INFO2("real", "", "", odbc_ver == SQL_OV_ODBC3 ? 24 : 7);

	case SYBFLT8:
		drec->sql_desc_concise_type = SQL_DOUBLE;
		drec->sql_desc_display_size = 24;	/* FIXME -- what should the correct size be? */
		SET_INFO2("float", "", "", odbc_ver == SQL_OV_ODBC3 ? 53 : 15);

	case SYBMONEY:
		/* TODO check money format returned by propretary ODBC, scale == 4 but we use 2 digits */
		drec->sql_desc_concise_type = SQL_DECIMAL;
		drec->sql_desc_octet_length = 21;
		drec->sql_desc_display_size = 21;
		drec->sql_desc_precision = 19;
		drec->sql_desc_scale     = 4;
		SET_INFO2("money", "$", "", 19);

	case SYBMONEY4:
		drec->sql_desc_concise_type = SQL_DECIMAL;
		drec->sql_desc_octet_length = 12;
		drec->sql_desc_display_size = 12;
		drec->sql_desc_precision = 10;
		drec->sql_desc_scale     = 4;
		SET_INFO2("money", "$", "", 10);

	case SYBDATETIME:
		drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
		drec->sql_desc_display_size = 23;
		drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
		drec->sql_desc_precision = 3;
		drec->sql_desc_scale     = 3;
		drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
		SET_INFO2("datetime", "'", "'", 23);

	case SYBDATETIME4:
		drec->sql_desc_concise_type = SQL_TYPE_TIMESTAMP;
		/* TODO dependent on precision (decimal second digits) */
		/* we always format using yyyy-mm-dd hh:mm:ss[.fff], see convert_tds2sql.c */
		drec->sql_desc_display_size = 19;
		drec->sql_desc_octet_length = sizeof(TIMESTAMP_STRUCT);
		drec->sql_desc_datetime_interval_code = SQL_CODE_TIMESTAMP;
		SET_INFO2("datetime", "'", "'", 16);

	/* The following two types are just Sybase types but as mainly our ODBC
	 * driver is much more compatible with Windows use attributes similar
	 * to MS one. For instance Sybase ODBC returns TIME into a TIME_STRUCT
	 * however this truncate the precision to 0 as TIME does not have
	 * fraction of seconds. Also Sybase ODBC have different concepts for
	 * PRECISION for many types and making these 2 types compatibles with
	 * Sybase would break this driver compatibility.
	 */
	case SYBTIME:
		drec->sql_desc_concise_type = SQL_SS_TIME2;
		drec->sql_desc_octet_length = sizeof(SQL_SS_TIME2_STRUCT);
		/* we always format using hh:mm:ss[.fff], see convert_tds2sql.c */
		drec->sql_desc_display_size = 12;
		drec->sql_desc_precision = 3;
		drec->sql_desc_scale     = 3;
		SET_INFO2("time", "'", "'", 12);

	case SYBDATE:
		drec->sql_desc_octet_length = sizeof(DATE_STRUCT);
		drec->sql_desc_concise_type = SQL_TYPE_DATE;
		/* we always format using yyyy-mm-dd, see convert_tds2sql.c */
		drec->sql_desc_display_size = 10;
		SET_INFO2("date", "'", "'", 10);

	case XSYBBINARY:
	case SYBBINARY:
		drec->sql_desc_concise_type = SQL_BINARY;
		drec->sql_desc_display_size = col->column_size * 2;
		/* handle TIMESTAMP using usertype */
		if (col->column_usertype == 80)
			SET_INFO("timestamp", "0x", "");
		SET_INFO("binary", "0x", "");

	case SYBLONGBINARY:
	case SYBIMAGE:
		drec->sql_desc_concise_type = SQL_LONGVARBINARY;
		drec->sql_desc_display_size = col->column_size * 2;
		SET_INFO("image", "0x", "");

	case XSYBVARBINARY:
	case SYBVARBINARY:
		drec->sql_desc_concise_type = SQL_VARBINARY;
		drec->sql_desc_display_size = col->column_size * 2;
		if (is_blob_col(col)) {
			drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
			drec->sql_desc_octet_length = drec->sql_desc_length =
				SQL_SS_LENGTH_UNLIMITED;
		}
		SET_INFO("varbinary", "0x", "");

	case SYBINTN:
	case SYBDATETIMN:
	case SYBFLTN:
	case SYBMONEYN:
	case SYBUINTN:
	case SYBTIMEN:
	case SYBDATEN:
		assert(0);

	case SYBVOID:
	case SYBINTERVAL:
	case SYBUNITEXT:
	case SYBXML:
	case SYBMSUDT:
		break;

#if (ODBCVER >= 0x0300)
	case SYBUNIQUE:
#ifdef SQL_GUID
		drec->sql_desc_concise_type = SQL_GUID;
#else
		drec->sql_desc_concise_type = SQL_CHAR;
#endif
		drec->sql_desc_display_size = 36;
		/* FIXME for Sybase ?? */
		SET_INFO2("uniqueidentifier", "'", "'", 36);
#endif

	case SYBMSXML:
		drec->sql_desc_concise_type = SQL_SS_XML;
		drec->sql_desc_display_size = SQL_SS_LENGTH_UNLIMITED;
		drec->sql_desc_octet_length = drec->sql_desc_length =
			SQL_SS_LENGTH_UNLIMITED;
		SET_INFO("xml", "'", "'");
	/* types already handled in other types, just to silent warnings */
	case SYBNUMERIC:
	case SYBDECIMAL:
	case SYBVARIANT:
	case SYBMSDATE:
	case SYBMSTIME:
	case SYBMSDATETIME2:
	case SYBMSDATETIMEOFFSET:
	case SYB5BIGDATETIME:
	case SYB5BIGTIME:
		break;
	}
	SET_INFO("", "", "");
}
Exemple #8
0
/**
 * 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;
}
Exemple #9
0
/**
 * Send one row of data to server
 * \tds
 * \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
 * \return TDS_SUCCESS or TDS_FAIL.
 */
TDSRET
tds_bcp_send_record(TDSSOCKET *tds, TDSBCPINFO *bcpinfo, tds_bcp_get_col_data get_col_data, tds_bcp_null_error null_error, int offset)
{
	TDSCOLUMN  *bindcol;
    int i, start_col = bcpinfo->next_col;
	TDSRET rc;

    tdsdump_log(TDS_DBG_FUNC, "tds_bcp_send_bcp_record(%p, %p, %p, %p, %d)\n", tds, bcpinfo, get_col_data, null_error, offset);

	if (tds->out_flag != TDS_BULK || tds_set_state(tds, TDS_WRITING) != TDS_WRITING)
		return TDS_FAIL;

    if (start_col > 0) {
        bindcol = bcpinfo->bindinfo->columns[start_col - 1];
        *bindcol->column_lenbind
            = MIN((TDS_INT) bindcol->column_bindlen - bcpinfo->text_sent,
                  *bindcol->column_lenbind);
        tds_put_n(tds, bindcol->column_varaddr, *bindcol->column_lenbind);
        bcpinfo->text_sent += *bindcol->column_lenbind;
        if ((TDS_UINT) bcpinfo->text_sent < bindcol->column_bindlen) {
            return TDS_SUCCESS; /* That's all for now. */
        } else if (!IS_TDS7_PLUS(tds->conn)) {
            bcpinfo->blob_cols++;
        }
        bcpinfo->next_col  = 0;
        bcpinfo->text_sent = 0;
    }

	if (IS_TDS7_PLUS(tds->conn)) {

        if (start_col == 0) {
            tds_put_byte(tds, TDS_ROW_TOKEN);   /* 0xd1 */
        }
        for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) {
	
			TDS_INT save_size;
			unsigned char *save_data;
			TDSBLOB blob;
            int /* bool */ has_text = 0;

			bindcol = bcpinfo->bindinfo->columns[i];

			/*
			 * Don't send the (meta)data for timestamp columns or
			 * identity columns unless indentity_insert is enabled.
			 */

			if ((!bcpinfo->identity_insert_on && bindcol->column_identity) || 
                bindcol->column_timestamp ||
                !tds_bcp_is_bound(bcpinfo, bindcol)) {
				continue;
			}

			rc = get_col_data(bcpinfo, bindcol, offset);
            if (rc == TDS_FAIL) {
				tdsdump_log(TDS_DBG_INFO1, "get_col_data (column %d) failed\n", i + 1);
				goto cleanup;
            } else if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */
                has_text = 1;
			}
			tdsdump_log(TDS_DBG_INFO1, "gotten column %d length %d null %d\n",
					i + 1, bindcol->bcp_column_data->datalen, bindcol->bcp_column_data->is_null);

			save_size = bindcol->column_cur_size;
			save_data = bindcol->column_data;
			assert(bindcol->column_data == NULL);
			if (bindcol->bcp_column_data->is_null) {
                if ( !bindcol->column_nullable
                     &&  !is_nullable_type(bindcol->on_server.column_type) ) {
                    return TDS_FAIL;
                }
				bindcol->column_cur_size = -1;
            } else if (has_text) {
                bindcol->column_cur_size = bindcol->bcp_column_data->datalen;
			} else if (is_blob_col(bindcol)) {
				bindcol->column_cur_size = bindcol->bcp_column_data->datalen;
				memset(&blob, 0, sizeof(blob));
				blob.textvalue = (TDS_CHAR *) bindcol->bcp_column_data->data;
				bindcol->column_data = (unsigned char *) &blob;
			} else {
				bindcol->column_cur_size = bindcol->bcp_column_data->datalen;
				bindcol->column_data = bindcol->bcp_column_data->data;
			}
			rc = bindcol->funcs->put_data(tds, bindcol, 1);
			bindcol->column_cur_size = save_size;
			bindcol->column_data = save_data;

			if (TDS_FAILED(rc))
				goto cleanup;
            else if (has_text) {
                bcpinfo->next_col = i + 1;
                /* bcpinfo->text_sent = 0; */
                break;
            }
		}
	}  /* IS_TDS7_PLUS */
	else {
      if (start_col == 0) {
		int row_pos;
		int row_sz_pos;
		int var_cols_written = 0;
		TDS_INT	 old_record_size = bcpinfo->bindinfo->row_size;
		unsigned char *record = bcpinfo->bindinfo->current_row;

		memset(record, '\0', old_record_size);	/* zero the rowbuffer */

		/*
		 * offset 0 = number of var columns
		 * offset 1 = row number.  zeroed (datasever assigns)
		 */
		row_pos = 2;

		rc = TDS_FAIL;
        if ((row_pos = tds_bcp_add_fixed_columns(bcpinfo, get_col_data, null_error, offset, record, row_pos)) < 0)
			goto cleanup;

		row_sz_pos = row_pos;

		/* potential variable columns to write */

        if ((row_pos = tds_bcp_add_variable_columns(bcpinfo, get_col_data, null_error, offset, record, row_pos, &var_cols_written)) < 0)
			goto cleanup;


		if (var_cols_written) {
			TDS_PUT_UA2(&record[row_sz_pos], row_pos);
			record[0] = var_cols_written;
		}

		tdsdump_log(TDS_DBG_INFO1, "old_record_size = %d new size = %d \n", old_record_size, row_pos);

		tds_put_smallint(tds, row_pos);
		tds_put_n(tds, record, row_pos);

		/* row is done, now handle any text/image data */

        bcpinfo->blob_cols = 0;
      }

        for (i = start_col; i < bcpinfo->bindinfo->num_cols; i++) {
			bindcol = bcpinfo->bindinfo->columns[i];
			if (is_blob_type(bindcol->column_type)) {
                /* Elide trailing NULLs */
                if (bindcol->bcp_column_data->is_null) {
                    int j;
                    for (j = i + 1;  j < bcpinfo->bindinfo->num_cols;  ++j) {
                        TDSCOLUMN *bindcol2 = bcpinfo->bindinfo->columns[j];
                        if (is_blob_type(bindcol2->column_type)
                            &&  !bindcol2->bcp_column_data->is_null) {
                            break;
                        }
                    }
                    if (j == bcpinfo->bindinfo->num_cols) {
                        i = j;
                        break;
                    }
                }

				rc = get_col_data(bcpinfo, bindcol, offset);
                if (rc == TDS_FAIL)
					goto cleanup;
				/* unknown but zero */
				tds_put_smallint(tds, 0);
                tds_put_byte(tds, (unsigned char) bindcol->column_type);
                tds_put_byte(tds, 0xff - bcpinfo->blob_cols);
				/*
				 * offset of txptr we stashed during variable
				 * column processing 
				 */
				tds_put_smallint(tds, bindcol->column_textpos);
				tds_put_int(tds, bindcol->bcp_column_data->datalen);
                if (rc != TDS_SUCCESS) { /* CS_BLK_HAS_TEXT? */
                    bcpinfo->next_col = i + 1;
                    /* bcpinfo->text_sent = 0; */
                    break;
                }
				tds_put_n(tds, bindcol->bcp_column_data->data, bindcol->bcp_column_data->datalen);
                bcpinfo->blob_cols++;

			}
		}
	}

    if (i == bcpinfo->bindinfo->num_cols) {
        tds_set_state(tds, TDS_SENDING);
        bcpinfo->next_col = 0;
    }
	return TDS_SUCCESS;

cleanup:
	tds_set_state(tds, TDS_SENDING);
	return rc;
}
Exemple #10
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;
}
Exemple #11
0
static void
test(int n, int type)
{
	int rc;
	TDS_INT result_type;
	char buf[1024], tmp[1024];
	TDSCOLUMN *curcol;
	char *src;
	int done_flags;
	int i;
	char prefix[32], suffix[32];

	sprintf(test_name, "test %d len %d", type, n);

	/* do a select and check all results */
	prefix[0] = 0;
	suffix[0] = 0;
	tmp[0] = 0;
	switch (type) {
	case 0:
		strcpy(suffix, "C280C290");
		break;
	case 1:
		/* try two invalid in different part */
		strcpy(prefix, "C480C290");
		strcpy(suffix, "C480C290");
		break;
	}

	for (i = 0; i < n; ++i)
		sprintf(strchr(tmp, 0), "%02X", 0x30 + (i % 10));
	sprintf(buf, "select convert(varchar(255), 0x%s%s%s)", prefix, tmp, suffix);
	rc = tds_submit_query(tds, buf);
	if (rc != TDS_SUCCESS) {
		fprintf(stderr, "tds_submit_query() failed\n");
		exit(1);
	}

	if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() failed\n");
		exit(1);
	}

	if (result_type != TDS_ROWFMT_RESULT) {
		fprintf(stderr, "expected row fmt() failed\n");
		exit(1);
	}

	if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() failed\n");
		exit(1);
	}

	if (result_type != TDS_ROW_RESULT) {
		fprintf(stderr, "expected row result() failed\n");
		exit(1);
	}

	/* force tds to convert from utf8 to iso8859-1 (even on Sybase) */
	tds_srv_charset_changed(tds->conn, "UTF-8");
	tds->current_results->columns[0]->char_conv = tds->conn->char_convs[client2server_chardata];

	rc = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
	if (rc != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() failed\n");
		exit(1);
	}

	curcol = tds->current_results->columns[0];
	src = (char*) curcol->column_data;

	if (is_blob_col(curcol)) {
		TDSBLOB *blob = (TDSBLOB *) src;

		src = blob->textvalue;
	}

	prefix[0] = 0;
	suffix[0] = 0;
	tmp[0] = 0;
	switch (type) {
	case 0:
		strcpy(suffix, "\x80\x90");
		break;
	case 1:
		/* try two invalid in different part */
		strcpy(prefix, "?\x90");
		strcpy(suffix, "?\x90");
		/* some platforms replace invalid sequence with a fixed char */
		if (invalid_char < 0)
			invalid_char = (unsigned char) src[0];
		prefix[0] = (char) invalid_char;
		suffix[0] = (char) invalid_char;
		break;
	}

	for (i = 0; i < n; ++i)
		sprintf(strchr(tmp, 0), "%c", "0123456789"[i % 10]);
	sprintf(buf, "%s%s%s", prefix, tmp, suffix);

	if (strlen(buf) != curcol->column_cur_size || strncmp(buf, src, curcol->column_cur_size) != 0) {
		int l = curcol->column_cur_size;

		if (l > 1000)
			l = 1000;
		strncpy(tmp, src, l);
		tmp[l] = 0;
		fprintf(stderr, "Wrong result in %s\n Got: '%s' len %d\n Expected: '%s' len %u\n", test_name, tmp,
			curcol->column_cur_size, buf, (unsigned int) strlen(buf));
		exit(1);
	}

	rc = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE);
	if (rc != TDS_SUCCESS || result_type == TDS_ROW_RESULT) {
		fprintf(stderr, "tds_process_tokens() unexpected return\n");
		exit(1);
	}

	while ((rc = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
		switch (result_type) {
		case TDS_NO_MORE_RESULTS:
			break;

		case TDS_DONE_RESULT:
		case TDS_DONEPROC_RESULT:
		case TDS_DONEINPROC_RESULT:
			if (!(done_flags & TDS_DONE_ERROR))
				break;

		default:
			fprintf(stderr, "tds_process_tokens() unexpected result_type\n");
			exit(1);
			break;
		}
	}
}
Exemple #12
0
static void
test0(const char *type, ...)
{
	char buf[512];
	CONV_RESULT cr;
	int rc;
	TDS_INT result_type;
	int done_flags;
	va_list ap;
	struct {
		const char *value;
		const char *result;
	} data[10];
	int num_data = 0, i_row;

	sprintf(buf, "CREATE TABLE #tmp(a %s)", type);
	exec_query(buf);

        va_start(ap, type);
	for (;;) {
		const char * value = va_arg(ap, const char *);
		const char * result;
		if (!value)
			break;
		result = va_arg(ap, const char *);
		if (!result)
			result = value;
		data[num_data].value = value;
		data[num_data].result = result;
		sprintf(buf, "INSERT INTO #tmp VALUES(CONVERT(%s,'%s'))", type, value);
		exec_query(buf);
		++num_data;
	}
        va_end(ap);

	assert(num_data > 0);

	/* execute it */
	rc = tds_submit_query(tds, "SELECT * FROM #tmp");
	if (rc != TDS_SUCCESS) {
		fprintf(stderr, "tds_submit_query() failed\n");
		exit(1);
	}

	if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() failed\n");
		exit(1);
	}

	if (result_type != TDS_ROWFMT_RESULT) {
		fprintf(stderr, "expected row fmt() failed\n");
		exit(1);
	}

	if (tds_process_tokens(tds, &result_type, NULL, TDS_TOKEN_RESULTS) != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() failed\n");
		exit(1);
	}

	if (result_type != TDS_ROW_RESULT) {
		fprintf(stderr, "expected row result() failed\n");
		exit(1);
	}

	i_row = 0;
	while ((rc = tds_process_tokens(tds, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW|TDS_RETURN_COMPUTE)) == TDS_SUCCESS && (result_type == TDS_ROW_RESULT || result_type == TDS_COMPUTE_RESULT)) {

		TDSCOLUMN *curcol = tds->current_results->columns[0];
		TDS_CHAR *src = (TDS_CHAR *) curcol->column_data;
		int conv_type = tds_get_conversion_type(curcol->column_type, curcol->column_size);

		assert(i_row < num_data);

		if (is_blob_col(curcol)) {
			TDSBLOB *blob = (TDSBLOB *) src;

			src = blob->textvalue;
		}

		if (tds_convert(test_context, conv_type, src, curcol->column_cur_size, SYBVARCHAR, &cr) < 0) {
			fprintf(stderr, "Error converting\n");
			g_result = 1;
		} else {
			if (strcmp(data[i_row].result, cr.c) != 0) {
				fprintf(stderr, "Failed! Is \n%s\nShould be\n%s\n", cr.c, data[i_row].result);
				g_result = 1;
			}
			free(cr.c);
		}
		++i_row;
	}

	if (rc != TDS_NO_MORE_RESULTS && rc != TDS_SUCCESS) {
		fprintf(stderr, "tds_process_tokens() unexpected return\n");
		exit(1);
	}

	while ((rc = tds_process_tokens(tds, &result_type, &done_flags, TDS_TOKEN_RESULTS)) == TDS_SUCCESS) {
		switch (result_type) {
		case TDS_NO_MORE_RESULTS:
			return;

		case TDS_DONE_RESULT:
		case TDS_DONEPROC_RESULT:
		case TDS_DONEINPROC_RESULT:
			if (!(done_flags & TDS_DONE_ERROR))
				break;

		default:
			fprintf(stderr, "tds_process_tokens() unexpected result_type\n");
			exit(1);
			break;
		}
	}

	exec_query("DROP TABLE #tmp");
}