⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 query.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
		dyn = tds_alloc_dynamic(tds, id);	}	if (!dyn)		return TDS_FAIL;		/* TDS5 sometimes cannot accept prepare so we need to store query */	if (!IS_TDS7_PLUS(tds)) {		dyn->query = strdup(query);		if (!dyn->query) {			tds_free_dynamic(tds, dyn);			return TDS_FAIL;		}	}	tds->cur_dyn = dyn;	if (dyn_out)		*dyn_out = dyn;	if (!IS_TDS50(tds) && !IS_TDS7_PLUS(tds)) {		dyn->emulated = 1;		return TDS_SUCCEED;	}	if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)		goto failure_nostate;	query_len = strlen(query);	if (IS_TDS7_PLUS(tds)) {		size_t definition_len = 0;		char *param_definition = NULL;		int converted_query_len;		const char *converted_query;		converted_query = tds_convert_string(tds, tds->char_convs[client2ucs2], query, query_len, &converted_query_len);		if (!converted_query)			goto failure;		param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);		if (!param_definition) {			tds_convert_string_free(query, converted_query);			goto failure;		}		tds->out_flag = TDS_RPC;		START_QUERY;		/* procedure name */		if (IS_TDS8_PLUS(tds)) {			tds_put_smallint(tds, -1);			tds_put_smallint(tds, TDS_SP_PREPARE);		} else {			tds_put_smallint(tds, 10);			TDS_PUT_N_AS_UCS2(tds, "sp_prepare");		}		tds_put_smallint(tds, 0);		/* return param handle (int) */		tds_put_byte(tds, 0);		tds_put_byte(tds, 1);	/* result */		tds_put_byte(tds, SYBINTN);		tds_put_byte(tds, 4);		tds_put_byte(tds, 0);		tds7_put_params_definition(tds, param_definition, definition_len);		tds7_put_query_params(tds, converted_query, converted_query_len);		tds_convert_string_free(query, converted_query);		free(param_definition);		/* 1 param ?? why ? flags ?? */		tds_put_byte(tds, 0);		tds_put_byte(tds, 0);		tds_put_byte(tds, SYBINTN);		tds_put_byte(tds, 4);		tds_put_byte(tds, 4);		tds_put_int(tds, 1);		tds->internal_sp_called = TDS_SP_PREPARE;	} else {		tds->out_flag = TDS_NORMAL;		id_len = strlen(dyn->id);		tds_put_byte(tds, TDS5_DYNAMIC_TOKEN);		tds_put_smallint(tds, query_len + id_len * 2 + 21);		tds_put_byte(tds, 0x01);		tds_put_byte(tds, 0x00);		tds_put_byte(tds, id_len);		tds_put_n(tds, dyn->id, id_len);		/* TODO ICONV convert string, do not put with tds_put_n */		/* TODO how to pass parameters type? like store procedures ? */		tds_put_smallint(tds, query_len + id_len + 16);		tds_put_n(tds, "create proc ", 12);		tds_put_n(tds, dyn->id, id_len);		tds_put_n(tds, " as ", 4);		tds_put_n(tds, query, query_len);	}	rc = tds_query_flush_packet(tds);	if (rc != TDS_FAIL)		return rc;failure:	/* TODO correct if writing fail ?? */	tds_set_state(tds, TDS_IDLE);failure_nostate:	tds->cur_dyn = NULL;	tds_free_dynamic(tds, dyn);	if (dyn_out)		*dyn_out = NULL;	return TDS_FAIL;}/** * Submit a prepared query with parameters * \param tds     state information for the socket and the TDS protocol * \param query   language query with given placeholders (?) * \param params  parameters to send * \return TDS_FAIL or TDS_SUCCEED */inttds_submit_execdirect(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params){	int query_len;	TDSCOLUMN *param;	char *tmp_id = NULL;	TDSDYNAMIC *dyn;	int id_len;	CHECK_TDS_EXTRA(tds);	CHECK_PARAMINFO_EXTRA(params);	if (!query)		return TDS_FAIL;	query_len = strlen(query);	if (IS_TDS7_PLUS(tds)) {		size_t definition_len = 0;		int i;		char *param_definition = NULL;		int converted_query_len;		const char *converted_query;		if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)			return TDS_FAIL;		converted_query = tds_convert_string(tds, tds->char_convs[client2ucs2], query, query_len, &converted_query_len);		if (!converted_query) {			tds_set_state(tds, TDS_IDLE);			return TDS_FAIL;		}		param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);		if (!param_definition) {			tds_convert_string_free(query, converted_query);			tds_set_state(tds, TDS_IDLE);			return TDS_FAIL;		}		tds->out_flag = TDS_RPC;		START_QUERY;		/* procedure name */		if (IS_TDS8_PLUS(tds)) {			tds_put_smallint(tds, -1);			tds_put_smallint(tds, TDS_SP_EXECUTESQL);		} else {			tds_put_smallint(tds, 13);			TDS_PUT_N_AS_UCS2(tds, "sp_executesql");		}		tds_put_smallint(tds, 0);		tds7_put_query_params(tds, converted_query, converted_query_len);		tds7_put_params_definition(tds, param_definition, definition_len);		tds_convert_string_free(query, converted_query);		free(param_definition);		for (i = 0; i < params->num_cols; i++) {			param = params->columns[i];			/* TODO check error */			tds_put_data_info(tds, param, 0);			tds_put_data(tds, param);		}		tds->internal_sp_called = TDS_SP_EXECUTESQL;		return tds_query_flush_packet(tds);	}	/* allocate a structure for this thing */	if (tds_get_dynid(tds, &tmp_id) == TDS_FAIL)		return TDS_FAIL;	dyn = tds_alloc_dynamic(tds, tmp_id);	free(tmp_id);	if (!dyn)		return TDS_FAIL;	/* check is no parameters */	if (params &&  !params->num_cols)		params = NULL;	/* TDS 4.2, emulate prepared statements */	/*	 * TODO Sybase seems to not support parameters in prepared execdirect	 * so use language or prepare and then exec	 */	if (!IS_TDS50(tds) || params) {		int ret = TDS_SUCCEED;		dyn->emulated = 1;		dyn->params = params;		dyn->query = strdup(query);		if (!dyn->query)			ret = TDS_FAIL;		if (ret != TDS_FAIL)			if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)				ret = TDS_FAIL;		if (ret != TDS_FAIL) {			ret = tds_send_emulated_execute(tds, dyn->query, dyn->params);			if (ret == TDS_SUCCEED)				ret = tds_query_flush_packet(tds);		}		/* do not free our parameters */		dyn->params = NULL;		tds_free_dynamic(tds, dyn);		return ret;	}	tds->cur_dyn = dyn;	if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)		return TDS_FAIL;	tds->out_flag = TDS_NORMAL;	id_len = strlen(dyn->id);	tds_put_byte(tds, TDS5_DYNAMIC_TOKEN);	tds_put_smallint(tds, query_len + id_len * 2 + 21);	tds_put_byte(tds, 0x08);	tds_put_byte(tds, params ? 0x01 : 0);	tds_put_byte(tds, id_len);	tds_put_n(tds, dyn->id, id_len);	/* TODO ICONV convert string, do not put with tds_put_n */	/* TODO how to pass parameters type? like store procedures ? */	tds_put_smallint(tds, query_len + id_len + 16);	tds_put_n(tds, "create proc ", 12);	tds_put_n(tds, dyn->id, id_len);	tds_put_n(tds, " as ", 4);	tds_put_n(tds, query, query_len);	if (params)		tds_put_params(tds, params, 0);	return tds_flush_packet(tds);}/** * Put data information to wire * \param tds    state information for the socket and the TDS protocol * \param curcol column where to store information * \param flags  bit flags on how to send data (use TDS_PUT_DATA_USE_NAME for use name information) * \return TDS_SUCCEED or TDS_FAIL */static inttds_put_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags){	int len;	CHECK_TDS_EXTRA(tds);	CHECK_COLUMN_EXTRA(curcol);	if (flags & TDS_PUT_DATA_USE_NAME) {		len = curcol->column_namelen;		tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting param_name \n");		if (IS_TDS7_PLUS(tds)) {			int converted_param_len;			const char *converted_param;			/* TODO use a fixed buffer to avoid error ? */			converted_param =				tds_convert_string(tds, tds->char_convs[client2ucs2], curcol->column_name, len,						   &converted_param_len);			if (!converted_param)				return TDS_FAIL;			if (!(flags & TDS_PUT_DATA_PREFIX_NAME)) {				tds_put_byte(tds, converted_param_len / 2);			} else {				tds_put_byte(tds, converted_param_len / 2 + 1);				tds_put_n(tds, "@", 2);			}			tds_put_n(tds, converted_param, converted_param_len);			tds_convert_string_free(curcol->column_name, converted_param);		} else {			/* TODO ICONV convert */			tds_put_byte(tds, len);	/* param name len */			tds_put_n(tds, curcol->column_name, len);		}	} else {		tds_put_byte(tds, 0x00);	/* param name len */	}	/*	 * TODO support other flags (use defaul null/no metadata)	 * bit 1 (2 as flag) in TDS7+ is "default value" bit 	 * (what's the meaning of "default value" ?)	 */	tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info putting status \n");	tds_put_byte(tds, curcol->column_output);	/* status (input) */	if (!IS_TDS7_PLUS(tds))		tds_put_int(tds, curcol->column_usertype);	/* usertype */	tds_put_byte(tds, curcol->on_server.column_type);	if (is_numeric_type(curcol->on_server.column_type)) {#if 1		tds_put_byte(tds, tds_numeric_bytes_per_prec[curcol->column_prec]);		tds_put_byte(tds, curcol->column_prec);		tds_put_byte(tds, curcol->column_scale);#else		TDS_NUMERIC *num = (TDS_NUMERIC *) curcol->column_data;		tds_put_byte(tds, tds_numeric_bytes_per_prec[num->precision]);		tds_put_byte(tds, num->precision);		tds_put_byte(tds, num->scale);#endif	} else {		switch (curcol->column_varint_size) {		case 0:			break;		case 1:			tds_put_byte(tds, MAX(MIN(curcol->column_size, 255), 1));			break;		case 2:			tds_put_smallint(tds, MAX(MIN(curcol->column_size, 8000), 1));			break;		case 4:			tds_put_int(tds, MAX(MIN(curcol->column_size, 0x7fffffff), 1));			break;		}	}	/* TDS8 output collate information */	if (IS_TDS8_PLUS(tds) && is_collate_type(curcol->on_server.column_type))		tds_put_n(tds, tds->collation, 5);	/* TODO needed in TDS4.2 ?? now is called only is TDS >= 5 */	if (!IS_TDS7_PLUS(tds)) {		tdsdump_log(TDS_DBG_ERROR, "HERE! \n");		tds_put_byte(tds, 0x00);	/* locale info length */	}	return TDS_SUCCEED;}/** * Calc information length in bytes (useful for calculating full packet length) * \param tds    state information for the socket and the TDS protocol * \param curcol column where to store information * \param flags  bit flags on how to send data (use TDS_PUT_DATA_USE_NAME for use name information) * \return TDS_SUCCEED or TDS_FAIL */static inttds_put_data_info_length(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags){	int len = 8;	CHECK_TDS_EXTRA(tds);	CHECK_COLUMN_EXTRA(curcol);#if ENABLE_EXTRA_CHECKS	if (IS_TDS7_PLUS(tds))		tdsdump_log(TDS_DBG_ERROR, "tds_put_data_info_length called with TDS7+\n");#endif	/* TODO ICONV convert string if needed (see also tds_put_data_info) */	if (flags & TDS_PUT_DATA_USE_NAME)		len += curcol->column_namelen;	if (is_numeric_type(curcol->on_server.column_type))		len += 2;	return len + curcol->column_varint_size;}/** * Write data to wire * \param tds     state information for the socket and the TDS protocol * \param curcol  column where store column information * \return TDS_FAIL on error or TDS_SUCCEED */static inttds_put_data(TDSSOCKET * tds, TDSCOLUMN * curcol){	unsigned char *src;	TDS_NUMERIC *num;	TDSBLOB *blob = NULL;	TDS_INT colsize;	CHECK_TDS_EXTRA(tds);	CHECK_COLUMN_EXTRA(curcol);	colsize = curcol->column_cur_size;	src = curcol->column_data;	tdsdump_log(TDS_DBG_INFO1, "tds_put_data: colsize = %d\n", (int) colsize);	if (colsize < 0) {		tdsdump_log(TDS_DBG_INFO1, "tds_put_data: null param\n");		switch (curcol->column_varint_size) {		case 4:			tds_put_int(tds, -1);			break;		case 2:			tds_put_smallint(tds, -1);			break;		default:			assert(curcol->column_varint_size);			/* FIXME not good for SYBLONGBINARY/SYBLONGCHAR (still not supported) */			tds_put_byte(tds, 0);			break;		}		return TDS_SUCCEED;	}	/*	 * TODO here we limit data sent with MIN, should mark somewhere	 * and inform client ??	 * Test proprietary behavior	 */	if (IS_TDS7_PLUS(tds)) {		const char *s;		int converted = 0;		tdsdump_log(TDS_DBG_INFO1, "tds_put_data: not null param varint_size = %d\n",			    curcol->column_varint_size);		if (is_blob_type(curcol->column_type)) {			blob = (TDSBLOB *) src;			src = (unsigned char *) blob->textvalue;		}		s = (char *) src;		/* convert string if needed */		if (curcol->char_conv && curcol->char_conv->flags != TDS_ENCODING_MEMCPY) {#if 0			/* TODO this case should be optimized */			/* we know converted bytes */			if (curcol->char_conv->client_charset.min_bytes_per_char == curcol->char_conv->client_charset.max_bytes_per_char 			    && curcol->char_conv->server_charset.min_bytes_per_char == curcol->char_conv->server_charset.max_bytes_per_char) {				converted_size = colsize * curcol->char_conv->server_charset.min_bytes_per_char / curcol->char_conv->client_charset.min_bytes_per_char;			} else {#endif			/* we need to convert data before */			/* TODO this can be a waste of memory... */			s = tds_convert_string(tds, curcol->char_conv, s, colsize, &colsize);			if (!s) {				/* FIXME this is a bad place to return error... */				/* TODO on memory failure we should compute comverted size and use chunks */				return TDS_FAIL;			}			converted = 1;		}					switch (curcol->column_varint_size) {		case 4:	/* It's a BLOB... */			blob = (TDSBLOB *) curcol->column_data;			colsize = MIN(colsize, 0x7fffffff);			/* mssql require only size */			tds_put_int(tds, colsize);			break;		case 2:			colsize = MIN(colsize, 8000);			tds_put_smallint(tds, colsize);			break;		case 1:			if (is_numeric_type(curcol->on_server.column_type))				colsize = tds_numeric_bytes_per_prec[((TDS_NUMERIC *) src)->precision];			colsize = MIN(colsize, 255);			tds_put_byte(tds, colsize);			break;		case 0:			/* TODO should be column_size */			colsize = tds_get_size_by_type(curcol->on_server.column_type);			break;		}		/* put real data */		if (is_numeric_type(curcol->on_server.column_type)) {			TDS_NUMERIC buf;			memcpy(&buf, src, sizeof(buf));			tdsdump_log(TDS_DBG_INFO1, "swapping numeric data...\n");			tds_swap_numeric(&buf);			tds_put_n(tds, buf.array, colsize);		} else if (blob) {			tds_put_n(tds, s, colsize);		} else {#ifdef WORDS_BIGENDIAN			unsigned char buf[64];			if (tds->emul_little_endian && !converted && colsize < 64) {				tdsdump_log(TDS_DBG_INFO1, "swapping coltype %d\n",					    tds_get_conversion_type(curcol->column_type, colsize));				memcpy(buf, s, colsize);				tds_swap_datatype(tds_get_conversion_type(curcol->column_type, colsize), buf);				s = (char *) buf;			}#endif			tds_put_n(tds, s, colsize);		}		if (converted)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -