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

📄 odbc_util.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns * Copyright (C) 2005, 2006 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 /* HAVE_CONFIG_H */#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#include <assert.h>#include "tdsodbc.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: odbc_util.c,v 1.94.2.1 2008/01/29 10:14:31 freddy77 Exp $");/** * \ingroup odbc_api * \defgroup odbc_util ODBC utility * Functions called within \c ODBC driver. *//** * \addtogroup odbc_util * @{  */static intodbc_set_stmt(TDS_STMT * stmt, char **dest, const char *sql, int sql_len){	char *p;	assert(dest == &stmt->prepared_query || dest == &stmt->query);	if (sql_len == SQL_NTS)		sql_len = strlen(sql);	else if (sql_len <= 0)		return SQL_ERROR;	/* TODO already NULL ?? */	tds_free_param_results(stmt->params);	stmt->params = NULL;	stmt->param_num = 0;	stmt->param_count = 0;	stmt->prepared_query_is_func = 0;	stmt->prepared_query_is_rpc = 0;	stmt->prepared_pos = NULL;	stmt->curr_param_row = 0;	stmt->num_param_rows = 1;	if (stmt->prepared_query)		TDS_ZERO_FREE(stmt->prepared_query);	if (stmt->query)		TDS_ZERO_FREE(stmt->query);	*dest = p = (char *) malloc(sql_len + 1);	if (!p)		return SQL_ERROR;	if (sql) {		memcpy(p, sql, sql_len);		p[sql_len] = 0;	} else {		p[0] = 0;	}	return SQL_SUCCESS;}intodbc_set_stmt_query(TDS_STMT * stmt, const char *sql, int sql_len){	return odbc_set_stmt(stmt, &stmt->query, sql, sql_len);}intodbc_set_stmt_prepared_query(TDS_STMT * stmt, const char *sql, int sql_len){	return odbc_set_stmt(stmt, &stmt->prepared_query, sql, sql_len);}voidodbc_set_return_status(struct _hstmt *stmt, unsigned int n_row){	TDSSOCKET *tds = stmt->dbc->tds_socket;	TDSCONTEXT *context = stmt->dbc->env->tds_ctx;	/* TODO handle different type results (functions) on mssql2k */	if (stmt->prepared_query_is_func && tds->has_status) {		struct _drecord *drec;		int len;		const TDS_DESC* axd = stmt->apd;		TDS_INTPTR len_offset;		char *data_ptr;		if (axd->header.sql_desc_count < 1)			return;		drec = &axd->records[0];		data_ptr = drec->sql_desc_data_ptr;		if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) {			len_offset = axd->header.sql_desc_bind_type * n_row;			if (axd->header.sql_desc_bind_offset_ptr)				len_offset += *axd->header.sql_desc_bind_offset_ptr;			data_ptr += len_offset;		} else {			len_offset = sizeof(SQLLEN) * n_row;			data_ptr += sizeof(SQLINTEGER) * n_row;		}#define LEN(ptr) *((SQLLEN*)(((char*)(ptr)) + len_offset))		len = convert_tds2sql(context, SYBINT4, (TDS_CHAR *) & tds->ret_status, sizeof(TDS_INT),				      drec->sql_desc_concise_type, (void *) data_ptr, drec->sql_desc_octet_length, NULL);		if (len < 0)			return /* SQL_ERROR */ ;		if (drec->sql_desc_indicator_ptr)			LEN(drec->sql_desc_indicator_ptr) = 0;		if (drec->sql_desc_octet_length_ptr)			LEN(drec->sql_desc_octet_length_ptr) = len;	}#undef LEN}voidodbc_set_return_params(struct _hstmt *stmt, unsigned int n_row){	TDSSOCKET *tds = stmt->dbc->tds_socket;	TDSPARAMINFO *info = tds->current_results;	TDSCONTEXT *context = stmt->dbc->env->tds_ctx;	int i_begin = stmt->prepared_query_is_func ? 1 : 0;	int i;	int nparam = i_begin;	/* I don't understand why but this happen -- freddy77 */	/* TODO check why, put an assert ? */	if (!info)		return;	for (i = 0; i < info->num_cols; ++i) {		const TDS_DESC* axd = stmt->apd;		const struct _drecord *drec_apd, *drec_ipd;		TDSCOLUMN *colinfo = info->columns[i];		TDS_CHAR *src;		int srclen;		SQLINTEGER len;		int c_type;		char *data_ptr;		TDS_INTPTR len_offset;		/* find next output parameter */		for (;;) {			drec_apd = NULL;			/* TODO best way to stop */			if (nparam >= axd->header.sql_desc_count || nparam >= stmt->ipd->header.sql_desc_count)				return;			drec_apd = &axd->records[nparam];			drec_ipd = &stmt->ipd->records[nparam];			if (stmt->ipd->records[nparam++].sql_desc_parameter_type != SQL_PARAM_INPUT)				break;		}		data_ptr = drec_apd->sql_desc_data_ptr;		if (axd->header.sql_desc_bind_type != SQL_BIND_BY_COLUMN) {			len_offset = axd->header.sql_desc_bind_type * n_row;			if (axd->header.sql_desc_bind_offset_ptr)				len_offset += *axd->header.sql_desc_bind_offset_ptr;			data_ptr += len_offset;		} else {			len_offset = sizeof(SQLLEN) * n_row;			data_ptr += odbc_get_octet_len(drec_apd->sql_desc_concise_type, drec_apd) * n_row;		}#define LEN(ptr) *((SQLLEN*)(((char*)(ptr)) + len_offset))		/* null parameter ? */		if (colinfo->column_cur_size < 0) {			/* FIXME error if NULL */			if (drec_apd->sql_desc_indicator_ptr)				LEN(drec_apd->sql_desc_indicator_ptr) = SQL_NULL_DATA;			continue;		}		src = (TDS_CHAR *) colinfo->column_data;		if (is_blob_type(colinfo->column_type))			src = ((TDSBLOB *) src)->textvalue;		srclen = colinfo->column_cur_size;		c_type = drec_apd->sql_desc_concise_type;		if (c_type == SQL_C_DEFAULT)			c_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type);		/* 		 * TODO why IPD ?? perhaps SQLBindParameter it's not correct ??		 * Or tests are wrong ??		 */		len = convert_tds2sql(context, tds_get_conversion_type(colinfo->column_type, colinfo->column_size), src, srclen,				      c_type, (void *) data_ptr, drec_apd->sql_desc_octet_length, drec_ipd);		/* TODO error handling */		if (len < 0)			return /* SQL_ERROR */ ;		if (drec_apd->sql_desc_indicator_ptr)			LEN(drec_apd->sql_desc_indicator_ptr) = 0;		if (drec_apd->sql_desc_octet_length_ptr)			LEN(drec_apd->sql_desc_octet_length_ptr) = len;#undef LEN	}}intodbc_get_string_size(int size, SQLCHAR * str){	if (str) {		if (size == SQL_NTS)			return strlen((const char *) str);		if (size >= 0)			return size;	}	/* SQL_NULL_DATA or any other strange value */	return 0;}/** * Convert type from database to ODBC */SQLSMALLINTodbc_server_to_sql_type(int col_type, int col_size){	/* FIXME finish */	switch ((TDS_SERVER_TYPE) col_type) {	case XSYBCHAR:	case SYBCHAR:		return SQL_CHAR;	case XSYBVARCHAR:	case SYBVARCHAR:		return SQL_VARCHAR;	case SYBTEXT:		return SQL_LONGVARCHAR;	case SYBBIT:	case SYBBITN:		return SQL_BIT;#if (ODBCVER >= 0x0300)	case SYBINT8:		/* TODO return numeric for odbc2 and convert bigint to numeric */		return SQL_BIGINT;#endif	case SYBINT4:		return SQL_INTEGER;	case SYBINT2:		return SQL_SMALLINT;	case SYBINT1:		return SQL_TINYINT;	case SYBINTN:		switch (col_size) {		case 1:			return SQL_TINYINT;		case 2:			return SQL_SMALLINT;		case 4:			return SQL_INTEGER;#if (ODBCVER >= 0x0300)		case 8:			return SQL_BIGINT;#endif		}		break;	case SYBREAL:		return SQL_REAL;	case SYBFLT8:		return SQL_DOUBLE;	case SYBFLTN:		switch (col_size) {		case 4:			return SQL_REAL;		case 8:			return SQL_DOUBLE;		}		break;	case SYBMONEY:	case SYBMONEY4:	case SYBMONEYN:		return SQL_FLOAT;	case SYBDATETIME:	case SYBDATETIME4:	case SYBDATETIMN:#if (ODBCVER >= 0x0300)		return SQL_TYPE_TIMESTAMP;#else		return SQL_TIMESTAMP;#endif	case XSYBBINARY:	case SYBBINARY:		return SQL_BINARY;	case SYBLONGBINARY:	case SYBIMAGE:		return SQL_LONGVARBINARY;	case XSYBVARBINARY:	case SYBVARBINARY:		return SQL_VARBINARY;	case SYBNUMERIC:	case SYBDECIMAL:		return SQL_NUMERIC;		/* TODO this is ODBC 3.5 */	case SYBNTEXT:	case SYBNVARCHAR:	case XSYBNVARCHAR:	case XSYBNCHAR:		break;#if (ODBCVER >= 0x0300)	case SYBUNIQUE:#ifdef SQL_GUID		return SQL_GUID;#else		return SQL_CHAR;#endif	case SYBVARIANT:		break;#endif		/*		 * TODO what should I do with these types ?? 		 * return other types can cause additional problems		 */	case SYBVOID:	case SYBSINT1:	case SYBUINT2:	case SYBUINT4:	case SYBUINT8:	case SYBUINT1:	case SYBDATE:	case SYBDATEN:	case SYB5INT8:	case SYBINTERVAL:	case SYBTIME:	case SYBTIMEN:	case SYBUINTN:	case SYBUNITEXT:	case SYBXML:		break;	}	return SQL_UNKNOWN_TYPE;}/** * Pass this an SQL_C_* type and get a SYB* type which most closely corresponds * to the SQL_C_* type. */intodbc_c_to_server_type(int c_type){	switch (c_type) {		/* FIXME this should be dependent on size of data !!! */	case SQL_C_BINARY:		return SYBBINARY;		/* TODO what happen if varchar is more than 255 characters long */	case SQL_C_CHAR:		return SYBVARCHAR;	case SQL_C_FLOAT:		return SYBREAL;	case SQL_C_DOUBLE:		return SYBFLT8;	case SQL_C_BIT:		return SYBBIT;#if (ODBCVER >= 0x0300)	case SQL_C_SBIGINT:	case SQL_C_UBIGINT:		return SYBINT8;#ifdef SQL_C_GUID	case SQL_C_GUID:		return SYBUNIQUE;#endif#endif	case SQL_C_LONG:	case SQL_C_SLONG:	case SQL_C_ULONG:		return SYBINT4;	case SQL_C_SHORT:	case SQL_C_SSHORT:	case SQL_C_USHORT:		return SYBINT2;	case SQL_C_TINYINT:	case SQL_C_STINYINT:	case SQL_C_UTINYINT:		return SYBINT1;		/* ODBC date formats are completely differect from SQL one */	case SQL_C_DATE:	case SQL_C_TIME:	case SQL_C_TIMESTAMP:	case SQL_C_TYPE_DATE:	case SQL_C_TYPE_TIME:	case SQL_C_TYPE_TIMESTAMP:		return SYBDATETIME;		/* ODBC numeric/decimal formats are completely differect from tds one */	case SQL_C_NUMERIC:		return SYBNUMERIC;		/* not supported */	case SQL_C_INTERVAL_YEAR:	case SQL_C_INTERVAL_MONTH:	case SQL_C_INTERVAL_DAY:	case SQL_C_INTERVAL_HOUR:	case SQL_C_INTERVAL_MINUTE:	case SQL_C_INTERVAL_SECOND:	case SQL_C_INTERVAL_YEAR_TO_MONTH:	case SQL_C_INTERVAL_DAY_TO_HOUR:	case SQL_C_INTERVAL_DAY_TO_MINUTE:	case SQL_C_INTERVAL_DAY_TO_SECOND:	case SQL_C_INTERVAL_HOUR_TO_MINUTE:	case SQL_C_INTERVAL_HOUR_TO_SECOND:	case SQL_C_INTERVAL_MINUTE_TO_SECOND:#ifdef SQL_C_WCHAR	case SQL_C_WCHAR:#endif		break;	}	return TDS_FAIL;}voidodbc_set_sql_type_info(TDSCOLUMN * col, struct _drecord *drec, SQLINTEGER odbc_ver){#define SET_INFO(type, prefix, suffix) \	drec->sql_desc_literal_prefix = prefix; \	drec->sql_desc_literal_suffix = suffix; \	drec->sql_desc_type_name = type; \	return;#define SET_INFO2(type, prefix, suffix, len) \	drec->sql_desc_length = len; \	SET_INFO(type, prefix, suffix)	/* FIXME finish, support for N type (nvarchar) */	switch (tds_get_conversion_type(col->column_type, col->column_size)) {	case XSYBCHAR:	case SYBCHAR:		SET_INFO("char", "'", "'");	case XSYBVARCHAR:	case SYBVARCHAR:		SET_INFO("varchar", "'", "'");	case SYBTEXT:		SET_INFO("text", "'", "'");	case SYBBIT:	case SYBBITN:		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 SYBINT1:		SET_INFO2("tinyint", "", "", 3);	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:		SET_INFO2("money", "$", "", 19);	case SYBMONEY4:		SET_INFO2("money", "$", "", 10);	case SYBDATETIME:		SET_INFO2("datetime", "'", "'", 23);	case SYBDATETIME4:		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:		SET_INFO("varbinary", "0x", "");	case SYBNUMERIC:		SET_INFO2("numeric", "", "", col->column_prec);	case SYBDECIMAL:		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_INFO("uniqueidentifier", "'", "'");	case SYBVARIANT:		/* SET_INFO("sql_variant", "", ""); */		break;#endif	}	SET_INFO("", "", "");#undef SET_INFO#undef SET_INFO2}SQLINTEGERodbc_sql_to_displaysize(int sqltype, TDSCOLUMN *col){	SQLINTEGER size = 0;	switch (sqltype) {	case SQL_CHAR:	case SQL_VARCHAR:	case SQL_LONGVARCHAR:		size = col->column_size;		break;	case SQL_BINARY:

⌨️ 快捷键说明

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