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

📄 query.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns * Copyright (C) 2006, 2007  Frediano Ziglio * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#if HAVE_CONFIG_H#include <config.h>#endif#include <stdarg.h>#include <stdio.h>#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#include <ctype.h>#include "tds.h"#include "tdsiconv.h"#include "tdsconvert.h"#include "tds_checks.h"#include "replacements.h"#ifdef DMALLOC#include <dmalloc.h>#endif#include <assert.h>TDS_RCSID(var, "$Id: query.c,v 1.217.2.1 2008/02/12 15:41:51 freddy77 Exp $");static void tds_put_params(TDSSOCKET * tds, TDSPARAMINFO * info, int flags);static void tds7_put_query_params(TDSSOCKET * tds, const char *query, int query_len);static void tds7_put_params_definition(TDSSOCKET * tds, const char *param_definition, size_t param_length);static int tds_put_data_info(TDSSOCKET * tds, TDSCOLUMN * curcol, int flags);static int tds_put_data(TDSSOCKET * tds, TDSCOLUMN * curcol);static char *tds7_build_param_def_from_query(TDSSOCKET * tds, const char* converted_query, int converted_query_len, TDSPARAMINFO * params, size_t *out_len);static char *tds7_build_param_def_from_params(TDSSOCKET * tds, const char* query, size_t query_len, TDSPARAMINFO * params, size_t *out_len);static int tds_send_emulated_execute(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params);static const char *tds_skip_comment(const char *s);static int tds_count_placeholders_ucs2le(const char *query, const char *query_end);#define TDS_PUT_DATA_USE_NAME 1#define TDS_PUT_DATA_PREFIX_NAME 2#undef MIN#define MIN(a,b) (((a) < (b)) ? (a) : (b))#undef MAX#define MAX(a,b) (((a) > (b)) ? (a) : (b))/* All manner of client to server submittal functions *//** * \ingroup libtds * \defgroup query Query * Function to handle query. *//** * \addtogroup query * @{  *//** * Accept an ASCII string, convert it to UCS2-LE * The input is null-terminated, but the output excludes the null. * \param buffer buffer where to store output * \param buf string to write * \return bytes written */static inttds_ascii_to_ucs2(char *buffer, const char *buf){	char *s;	assert(buffer && buf && *buf); /* This is an internal function.  Call it correctly. */	for (s = buffer; *buf != '\0'; ++buf) {		*s++ = *buf;		*s++ = '\0';	}	return s - buffer;}#define TDS_PUT_N_AS_UCS2(tds, s) do { \	char buffer[sizeof(s)*2-2]; \	tds_put_n(tds, buffer, tds_ascii_to_ucs2(buffer, s)); \} while(0)/** * Convert a string in an allocated buffer * \param tds        state information for the socket and the TDS protocol * \param char_conv  information about the encodings involved * \param s          input string * \param len        input string length (in bytes), -1 for null terminated * \param out_len    returned output length (in bytes) * \return string allocated (or input pointer if no conversion required) or NULL if error */static const char *tds_convert_string(TDSSOCKET * tds, const TDSICONV * char_conv, const char *s, int len, int *out_len){	char *buf;	const char *ib;	char *ob;	size_t il, ol;	/* char_conv is only mostly const */	TDS_ERRNO_MESSAGE_FLAGS *suppress = (TDS_ERRNO_MESSAGE_FLAGS*) &char_conv->suppress;	CHECK_TDS_EXTRA(tds);	if (len < 0)		len = strlen(s);	if (char_conv->flags == TDS_ENCODING_MEMCPY) {		*out_len = len;		return s;	}	/* allocate needed buffer (+1 is to exclude 0 case) */	ol = len * char_conv->server_charset.max_bytes_per_char / char_conv->client_charset.min_bytes_per_char + 1;	buf = (char *) malloc(ol);	if (!buf)		return NULL;	ib = s;	il = len;	ob = buf;	memset(suppress, 0, sizeof(char_conv->suppress));	if (tds_iconv(tds, char_conv, to_server, &ib, &il, &ob, &ol) == (size_t)-1) {		free(buf);		return NULL;	}	*out_len = ob - buf;	return buf;}#if ENABLE_EXTRA_CHECKSstatic voidtds_convert_string_free(const char *original, const char *converted){	if (original != converted)		free((char *) converted);}#else#define tds_convert_string_free(original, converted) \	do { if (original != converted) free((char*) converted); } while(0)#endifstatic inttds_query_flush_packet(TDSSOCKET *tds){	/* TODO depend on result ?? */	tds_set_state(tds, TDS_PENDING);	return tds_flush_packet(tds);}/** * tds_submit_query() sends a language string to the database server for * processing.  TDS 4.2 is a plain text message with a packet type of 0x01, * TDS 7.0 is a unicode string with packet type 0x01, and TDS 5.0 uses a  * TDS_LANGUAGE_TOKEN to encapsulate the query and a packet type of 0x0f. * \param tds state information for the socket and the TDS protocol * \param query language query to submit * \return TDS_FAIL or TDS_SUCCEED */inttds_submit_query(TDSSOCKET * tds, const char *query){	return tds_submit_query_params(tds, query, NULL);}static char *tds5_fix_dot_query(const char *query, int *query_len, TDSPARAMINFO * params){	int i, pos, l;	const char *e, *s;	int size = *query_len + 30;	char *out = (char *) malloc(size);	if (!out)		return NULL;	pos = 0;	s = query;	for (i = 0;; ++i) {		e = tds_next_placeholder(s);		l = e ? e - s : strlen(s);		if (pos + l + 12 >= size) {			char *p;			size = pos + l + 30;			p = realloc(out, size);			if (!p) {				free(out);				return NULL;			}			out = p;		}		memcpy(out + pos, s, l);		pos += l;		if (!e)			break;		pos += sprintf(out + pos, "@P%d", i + 1);		if (i >= params->num_cols) {			free(out);			return NULL;		}		sprintf(params->columns[i]->column_name, "@P%d", i + 1);		params->columns[i]->column_namelen = strlen(params->columns[i]->column_name);		s = e + 1;	}	out[pos] = 0;	*query_len = pos;	return out;}#ifdef ENABLE_DEVELOPINGstatic const TDS_UCHAR tds9_query_start[] = {	/* total length */	0x16, 0, 0, 0,	/* length */	0x12, 0, 0, 0,	/* type */	0x02, 0,	/* transaction */	0, 0, 0, 0, 0, 0, 0, 0,	/* request count */	1, 0, 0, 0};#define START_QUERY \do { \	if (IS_TDS90(tds)) \		tds_start_query(tds); \} while(0)static voidtds_start_query(TDSSOCKET *tds){	tds_put_n(tds, tds9_query_start, 10);	tds_put_n(tds, tds->tds9_transaction, 8);	tds_put_n(tds, tds9_query_start + 10 + 8, 4);}#else#define START_QUERY do { ; } while(0)#endif/** * tds_submit_query_params() sends a language string to the database server for * processing.  TDS 4.2 is a plain text message with a packet type of 0x01, * TDS 7.0 is a unicode string with packet type 0x01, and TDS 5.0 uses a * TDS_LANGUAGE_TOKEN to encapsulate the query and a packet type of 0x0f. * \param tds state information for the socket and the TDS protocol * \param query  language query to submit * \param params parameters of query * \return TDS_FAIL or TDS_SUCCEED */inttds_submit_query_params(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params){	int query_len;	int num_params = params ? params->num_cols : 0; 	CHECK_TDS_EXTRA(tds);	if (params)		CHECK_PARAMINFO_EXTRA(params); 	if (!query)		return TDS_FAIL; 	if (tds_set_state(tds, TDS_QUERYING) != TDS_QUERYING)		return TDS_FAIL; 	query_len = strlen(query); 	if (IS_TDS50(tds)) {		char *new_query = NULL;		/* are there '?' style parameters ? */		if (tds_next_placeholder(query)) {			if ((new_query = tds5_fix_dot_query(query, &query_len, params)) == NULL) {				tds_set_state(tds, TDS_IDLE);				return TDS_FAIL;			}			query = new_query;		}		tds->out_flag = TDS_NORMAL;		tds_put_byte(tds, TDS_LANGUAGE_TOKEN);		/* TODO ICONV use converted size, not input size and convert string */		tds_put_int(tds, query_len + 1);		tds_put_byte(tds, params ? 1 : 0);  /* 1 if there are params, 0 otherwise */		tds_put_n(tds, query, query_len);		if (params) {			/* add on parameters */			tds_put_params(tds, params, params->columns[0]->column_name[0] ? TDS_PUT_DATA_USE_NAME : 0);		}		free(new_query);	} else if (!IS_TDS7_PLUS(tds) || !params || !params->num_cols) {		tds->out_flag = TDS_QUERY;		START_QUERY;		tds_put_string(tds, query, query_len);	} else {		TDSCOLUMN *param;		size_t definition_len;		int count, i;		char *param_definition;		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) {			tds_set_state(tds, TDS_IDLE);			return TDS_FAIL;		}		count = tds_count_placeholders_ucs2le(converted_query, converted_query + converted_query_len); 		if (!count) {			param_definition = tds7_build_param_def_from_params(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;			}		} else {			/*			 * TODO perhaps functions that calls tds7_build_param_def_from_query			 * should call also tds7_build_param_def_from_params ??			 */			param_definition = tds7_build_param_def_from_query(tds, converted_query, converted_query_len, params, &definition_len);			if (!param_definition) {				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); 		/* string with sql statement */		if (!count) {			tds_put_byte(tds, 0);			tds_put_byte(tds, 0);			tds_put_byte(tds, SYBNTEXT);	/* must be Ntype */			tds_put_int(tds, converted_query_len);			if (IS_TDS8_PLUS(tds))				tds_put_n(tds, tds->collation, 5);			tds_put_int(tds, converted_query_len);			tds_put_n(tds, converted_query, converted_query_len);		} else {			tds7_put_query_params(tds, converted_query, converted_query_len);		}		tds_convert_string_free(query, converted_query); 		tds7_put_params_definition(tds, param_definition, definition_len);		free(param_definition); 		for (i = 0; i < num_params; 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);}inttds_submit_queryf(TDSSOCKET * tds, const char *queryf, ...){	va_list ap;	char *query = NULL;	int rc = TDS_FAIL;	CHECK_TDS_EXTRA(tds);	va_start(ap, queryf);	if (vasprintf(&query, queryf, ap) >= 0) {		rc = tds_submit_query(tds, query);		free(query);	}	va_end(ap);	return rc;}static const char *tds_skip_comment(const char *s){	const char *p = s;	if (*p == '-' && p[1] == '-') {		for (;*++p != '\0';)			if (*p == '\n')				return p;	} else if (*p == '/' && p[1] == '*') {		++p;		for(;*++p != '\0';)			if (*p == '*' && p[1] == '/')				return p + 2;	} else		++p;	return p;}/** * Skip quoting string (like 'sfsf', "dflkdj" or [dfkjd]) * @param s pointer to first quoting character (should be '," or [) * @return character after quoting */const char *tds_skip_quoted(const char *s){	const char *p = s;	char quote = (*s == '[') ? ']' : *s;	for (; *++p;) {		if (*p == quote) {			if (*++p != quote)				return p;		}	}	return p;}/** * Get position of next placeholder * @param start pointer to part of query to search * @return next placeholder or NULL if not found */const char *tds_next_placeholder(const char *start){	const char *p = start;	if (!p)		return NULL;	for (;;) {		switch (*p) {		case '\0':			return NULL;		case '\'':		case '\"':		case '[':			p = tds_skip_quoted(p);			break;		case '-':		case '/':			p = tds_skip_comment(p);			break;		case '?':			return p;		default:			++p;			break;		}	}}/** * Count the number of placeholders in query */inttds_count_placeholders(const char *query){	const char *p = query - 1;	int count = 0;	for (;; ++count) {		if (!(p = tds_next_placeholder(p + 1)))			return count;	}}static const char *

⌨️ 快捷键说明

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