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

📄 convert.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 * * 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 TIME_WITH_SYS_TIME# if HAVE_SYS_TIME_H#  include <sys/time.h># endif# include <time.h>#else# if HAVE_SYS_TIME_H#  include <sys/time.h># else#  include <time.h># endif#endif#include <assert.h>#include <ctype.h>#if HAVE_ERRNO_H#include <errno.h>#endif /* HAVE_ERRNO_H */#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#if HAVE_STRINGS_H#include <strings.h>#endif /* HAVE_STRINGS_H */#include "tds.h"#include "tdsconvert.h"#include "tdsbytes.h"#include "replacements.h"#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: convert.c,v 1.179.2.1 2008/02/04 07:55:39 freddy77 Exp $");typedef unsigned short utf16_t;static TDS_INT tds_convert_int1(int srctype, const TDS_CHAR * src, int desttype, CONV_RESULT * cr);static TDS_INT tds_convert_int2(int srctype, const TDS_CHAR * src, int desttype, CONV_RESULT * cr);static TDS_INT tds_convert_int4(int srctype, const TDS_CHAR * src, int desttype, CONV_RESULT * cr);static TDS_INT tds_convert_int8(int srctype, const TDS_CHAR * src, int desttype, CONV_RESULT * cr);static int string_to_datetime(const char *datestr, int desttype, CONV_RESULT * cr);static int is_dd_mon_yyyy(char *t);static int store_dd_mon_yyy_date(char *datestr, struct tds_time *t);#define test_alloc(x) {if ((x)==NULL) return TDS_CONVERT_NOMEM;}#define IS_TINYINT(x) ( 0 <= (x) && (x) <= 0xff )#define IS_SMALLINT(x) ( -32768 <= (x) && (x) <= 32767 )/* * f77: I don't write -2147483648, some compiler seem to have some problem  * with this constant although is a valid 32bit value */#define TDS_INT_MIN (-2147483647l-1l)#define TDS_INT_MAX 2147483647l#define IS_INT(x) (TDS_INT_MIN <= (x) && (x) <= TDS_INT_MAX)#define TDS_INT8_MAX ((((TDS_INT8) 0x7fffffffl) << 32) + 0xfffffffflu)#define TDS_INT8_MIN  (((TDS_INT8) (-0x7fffffffl-1)) << 32)#define IS_INT8(x) (TDS_INT8_MIN <= (x) && (x) <= TDS_INT8_MAX)/** * \ingroup libtds * \defgroup convert Conversion * Conversions between datatypes.  Supports, for example, dbconvert().   *//** * \addtogroup convert * @{  *//** * convert a number in string to a TDSNUMERIC * @return sizeof(TDS_NUMERIC) on success, TDS_CONVERT_* failure code on failure  */static int string_to_numeric(const char *instr, const char *pend, CONV_RESULT * cr);/** * convert a zero terminated string to NUMERIC * @return sizeof(TDS_NUMERIC) on success, TDS_CONVERT_* failure code on failure  */static int stringz_to_numeric(const char *instr, CONV_RESULT * cr);static TDS_INT string_to_int(const char *buf, const char *pend, TDS_INT * res);static TDS_INT string_to_int8(const char *buf, const char *pend, TDS_INT8 * res);static int store_hour(const char *, const char *, struct tds_time *);static int store_time(const char *, struct tds_time *);static int store_yymmdd_date(const char *, struct tds_time *);static int store_monthname(const char *, struct tds_time *);static int store_numeric_date(const char *, struct tds_time *);static int store_mday(const char *, struct tds_time *);static int store_year(int, struct tds_time *);/* static int days_this_year (int years); */static int is_timeformat(const char *);static int is_numeric(const char *);static int is_alphabetic(const char *);static int is_ampm(const char *);#define is_monthname(s) (store_monthname(s, NULL) >= 0)static int is_numeric_dateformat(const char *);#if 0static TDS_UINT utf16len(const utf16_t * s);static const char *tds_prtype(int token);#endifconst char tds_hex_digits[16] = "0123456789abcdef";/** * Return type suitable for conversions (convert all nullable types to  * fixed type) * @param srctype type to convert * @param colsize size of type * @result type for conversion */inttds_get_conversion_type(int srctype, int colsize){	switch (srctype) {	case SYBINTN:		switch (colsize) {		case 8:			return SYBINT8;		case 4:			return SYBINT4;		case 2:			return SYBINT2;		case 1:			return SYBINT1;		}		break;	case SYBFLTN:		switch (colsize) {		case 8:			return SYBFLT8;		case 4:			return SYBREAL;		}		break;	case SYBDATETIMN:		switch (colsize) {		case 8:			return SYBDATETIME;		case 4:			return SYBDATETIME4;		}		break;	case SYBMONEYN:		switch (colsize) {		case 8:			return SYBMONEY;		case 4:			return SYBMONEY4;		}		break;		/*		 * altough tds_convert handle SYBBITN other routine use this		 * function to retrieve not variant type		 */	case SYBBITN:		return SYBBIT;		break;	}	return srctype;}/** * Copy a terminated string to result and return len or TDS_CONVERT_NOMEM */static TDS_INTstring_to_result(int desttype, const char *s, CONV_RESULT * cr){	size_t len = strlen(s);	if (desttype != TDS_CONVERT_CHAR) {		cr->c = (TDS_CHAR *) malloc(len + 1);		test_alloc(cr->c);		memcpy(cr->c, s, len + 1);	} else {		memcpy(cr->cc.c, s, len < cr->cc.len ? len : cr->cc.len);	}	return len;}#define string_to_result(s, cr) \	string_to_result(desttype, s, cr)/** * Copy binary data to to result and return len or TDS_CONVERT_NOMEM */static TDS_INTbinary_to_result(int desttype, const void *data, size_t len, CONV_RESULT * cr){	if (desttype != TDS_CONVERT_BINARY) {		cr->ib = (TDS_CHAR *) malloc(len);		test_alloc(cr->ib);		memcpy(cr->ib, data, len);	} else {		memcpy(cr->cb.ib, data, len < cr->cb.len ? len : cr->cb.len);	}	return len;}#define binary_to_result(data, len, cr) \	binary_to_result(desttype, data, len, cr)#define CASE_ALL_CHAR \	SYBCHAR: case SYBVARCHAR: case SYBTEXT: case XSYBCHAR: case XSYBVARCHAR#define CASE_ALL_BINARY \	SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY: case TDS_CONVERT_BINARY/* TODO implement me *//*static TDS_INT tds_convert_ntext(int srctype,TDS_CHAR *src,TDS_UINT srclen,      int desttype, CONV_RESULT *cr){      return TDS_CONVERT_NOAVAIL;}*/static TDS_INTtds_convert_binary(int srctype, const TDS_UCHAR * src, TDS_INT srclen, int desttype, CONV_RESULT * cr){	int cplen;	int s;	char *c;	switch (desttype) {	case TDS_CONVERT_CHAR:		cplen = srclen * 2;		if (cplen > cr->cc.len)			cplen = cr->cc.len;		c = cr->cc.c;		for (s = 0; cplen >= 2; ++s, cplen -= 2) {			*c++ = tds_hex_digits[src[s]>>4];			*c++ = tds_hex_digits[src[s]&0xF];		}		if (cplen)			*c++ = tds_hex_digits[src[s]>>4];		return srclen * 2;	case CASE_ALL_CHAR:		/*		 * NOTE: Do not prepend 0x to string.  		 * The libraries all expect a bare string, without a 0x prefix. 		 * Applications such as isql and query analyzer provide the "0x" prefix.		 */		/* 2 * source length + 1 for terminator */		cr->c = (TDS_CHAR *) malloc((srclen * 2) + 1);		test_alloc(cr->c);		c = cr->c;		for (s = 0; s < srclen; s++) {			*c++ = tds_hex_digits[src[s]>>4];			*c++ = tds_hex_digits[src[s]&0xF];		}		*c = '\0';		return (srclen * 2);		break;	case CASE_ALL_BINARY:		return binary_to_result(src, srclen, cr);		break;	case SYBINT1:	case SYBINT2:	case SYBINT4:	case SYBINT8:	case SYBMONEY4:	case SYBMONEY:	case SYBREAL:	case SYBFLT8:		cplen = tds_get_size_by_type(desttype);		if (srclen >= cplen)			srclen = cplen;		memcpy(cr, src, srclen);		memset(((char*) cr) + srclen, 0, cplen - srclen);		return cplen;		break;		/* conversions not allowed */	case SYBDATETIME4:	case SYBDATETIME:	case SYBDATETIMN:		/* TODO should we do some test for these types or work as ints ?? */	case SYBDECIMAL:	case SYBNUMERIC:	case SYBBIT:	case SYBBITN:	default:		break;	}	return TDS_CONVERT_NOAVAIL;}static TDS_INTtds_convert_char(int srctype, const TDS_CHAR * src, TDS_UINT srclen, int desttype, CONV_RESULT * cr){	unsigned int i, j;	unsigned char hex1;	TDS_INT8 mymoney;	char mynumber[39];	const char *ptr, *pend;	int point_found;	unsigned int places;	TDS_INT tds_i;	TDS_INT8 tds_i8;	TDS_INT rc;	TDS_CHAR *ib;	switch (desttype) {	case TDS_CONVERT_CHAR:		memcpy(cr->cc.c, src, srclen < cr->cc.len ? srclen : cr->cc.len);		return srclen;	case CASE_ALL_CHAR:		cr->c = (TDS_CHAR *) malloc(srclen + 1);		test_alloc(cr->c);		memcpy(cr->c, src, srclen);		cr->c[srclen] = 0;		return srclen;		break;	case CASE_ALL_BINARY:		/* skip leading "0x" or "0X" */		if (src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) {			src += 2;			srclen -= 2;		}		/* ignore trailing blanks and nulls */		/* FIXME is good to ignore null ?? */		while (srclen > 0 && (src[srclen - 1] == ' ' || src[srclen - 1] == '\0'))			--srclen;		/* a binary string output will be half the length of */		/* the string which represents it in hexadecimal     */		/* if srclen if odd we must add a "0" before ... */		j = 0;		/* number where to start converting */		if (srclen & 1) {			++srclen;			j = 1;			--src;		}		ib = cr->cb.ib;		if (desttype != TDS_CONVERT_BINARY) {			cr->ib = (TDS_CHAR *) malloc(srclen / 2);			test_alloc(cr->ib);			ib = cr->ib;		}		for (i = srclen; i > j;) {			hex1 = src[--i];			if ('0' <= hex1 && hex1 <= '9')				hex1 &= 0x0f;			else {				hex1 &= 0x20 ^ 0xff;	/* mask off 0x20 to ensure upper case */				if ('A' <= hex1 && hex1 <= 'F') {					hex1 -= ('A' - 10);				} else {					tdsdump_log(TDS_DBG_INFO1,						    "error_handler:  attempt to convert data stopped by syntax error in source field \n");					return TDS_CONVERT_SYNTAX;				}			}			assert(hex1 < 0x10);			if (desttype == TDS_CONVERT_BINARY && (i/2) >= cr->cb.len)				continue;			if (i & 1)				ib[i / 2] = hex1;			else				ib[i / 2] |= hex1 << 4;		}		return srclen / 2;		break;	case SYBINT1:		if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)			return rc;		if (!IS_TINYINT(tds_i))			return TDS_CONVERT_OVERFLOW;		cr->ti = tds_i;		return sizeof(TDS_TINYINT);		break;	case SYBINT2:		if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)			return rc;		if (!IS_SMALLINT(tds_i))			return TDS_CONVERT_OVERFLOW;		cr->si = tds_i;		return sizeof(TDS_SMALLINT);		break;	case SYBINT4:		if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)			return rc;		cr->i = tds_i;		return sizeof(TDS_INT);		break;	case SYBINT8:		if ((rc = string_to_int8(src, src + srclen, &tds_i8)) < 0)			return rc;		cr->bi = tds_i8;		return sizeof(TDS_INT8);		break;	case SYBFLT8:		/* FIXME not null terminated */		/* TODO check syntax and overflow */		cr->f = atof(src);		return sizeof(TDS_FLOAT);		break;	case SYBREAL:		/* FIXME not null terminated */		/* TODO check syntax and overflow */		cr->r = atof(src);		return sizeof(TDS_REAL);		break;	case SYBBIT:	case SYBBITN:		if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)			return rc;		cr->ti = tds_i ? 1 : 0;		return sizeof(TDS_TINYINT);		break;	case SYBMONEY:	case SYBMONEY4:		/* TODO code similar to string_to_numeric... */		i = 0;		places = 0;		point_found = 0;		pend = src + srclen;		/* skip leading blanks */		for (ptr = src; ptr != pend && *ptr == ' '; ++ptr);		switch (ptr != pend ? *ptr : 0) {		case '-':			mynumber[i++] = '-';			/* fall through */		case '+':			ptr++;			for (; ptr != pend && *ptr == ' '; ++ptr);			break;		}		for (; ptr != pend; ptr++) {	/* deal with the rest */			if (isdigit((unsigned char) *ptr)) {	/* it's a number */				/* no more than 4 decimal digits */				if (places < 4)					mynumber[i++] = *ptr;				/* assure not buffer overflow */				if (i == 30)					return TDS_CONVERT_OVERFLOW;				if (point_found) {	/* if we passed a decimal point */					/* count digits after that point  */					++places;				}			} else if (*ptr == '.') {	/* found a decimal point */				if (point_found)	/* already had one. error */					return TDS_CONVERT_SYNTAX;				point_found = 1;			} else	/* first invalid character */				return TDS_CONVERT_SYNTAX;	/* lose the rest.          */		}		for (j = places; j < 4; j++)			mynumber[i++] = '0';		mynumber[i] = 0;		/* FIXME overflow not handled */		if (desttype == SYBMONEY) {			mymoney = atoll(mynumber);			cr->m.mny = mymoney;			return sizeof(TDS_MONEY);		} else {			cr->m4.mny4 = atol(mynumber);			return sizeof(TDS_MONEY4);		}		break;	case SYBDATETIME:		/* FIXME not null terminated */		return string_to_datetime(src, SYBDATETIME, cr);		break;	case SYBDATETIME4:		/* FIXME not null terminated */		return string_to_datetime(src, SYBDATETIME4, cr);		break;	case SYBNUMERIC:	case SYBDECIMAL:		return string_to_numeric(src, src + srclen, cr);		break;	case SYBUNIQUE:{			unsigned n = 0;			char c;			/* 			 * format:	 XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 			 * or 		{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} 			 * or 		 XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX  			 * or 		{XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX} 			 * SQL seem to ignore the additional braces.			 */			if (srclen < (32 + 3))				return TDS_CONVERT_SYNTAX;			if (src[0] == '{') {				TDS_UINT last = (src[8+1 + 4+1 + 4+1 + 4 + 1] == '-') ? 32+4+1 : 32+3+1;				if (srclen <= last || src[last] != '}')					return TDS_CONVERT_SYNTAX;				++src;			}			/* 			 * Test each character and get value.  			 * sscanf works if the number terminates with less digits. 			 */			for (i = 0; i < 32 + 3; ++i) {				c = src[i];				switch (i) {				case 8:					if (c != '-')						return TDS_CONVERT_SYNTAX;					cr->u.Data1 = n;					n = 0;					break;				case 8+1 + 4:					if (c != '-')						return TDS_CONVERT_SYNTAX;

⌨️ 快捷键说明

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