odbcconvert.c

来自「这个是内存数据库的客户端」· C语言 代码 · 共 2,426 行 · 第 1/5 页

C
2,426
字号
/* * The contents of this file are subject to the MonetDB Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Original Code is the MonetDB Database System. * * The Initial Developer of the Original Code is CWI. * Portions created by CWI are Copyright (C) 1997-2007 CWI. * All Rights Reserved. */#include "ODBCGlobal.h"#include "ODBCStmt.h"#include "ODBCUtil.h"#include <errno.h>#include <time.h>#ifdef HAVE_STRINGS_H#include <strings.h>		/* for strncasecmp */#endif#if SIZEOF_INT==8# define ULL_CONSTANT(val)	(val)# define O_ULLFMT		"u"#elif SIZEOF_LONG==8# define ULL_CONSTANT(val)	(val##UL)# define O_ULLFMT		"lu"#elif defined(HAVE_LONG_LONG)# define ULL_CONSTANT(val)	(val##ULL)# define O_ULLFMT		"llu"#elif defined(HAVE___INT64)# define ULL_CONSTANT(val)	(val##ui64)# define O_ULLFMT		"I64u"#endif#define MAXBIGNUM10	ULL_CONSTANT(1844674407370955161)	/* (2**64-1)/10 */#define MAXBIGNUMLAST	'5'	/* (2**64-1)%10 */#define space(c)	((c) == ' ' || (c) == '\t')typedef struct {	unsigned char precision; /* total number of digits */	signed char scale;	/* how far to shift decimal point (>				   0: shift left, i.e. number has				   fraction; < 0: shift right,				   i.e. multiply with power of 10) */	unsigned char sign;	/* 1 pos, 0 neg */	SQLUBIGINT val;		/* the value */} bignum_t;#ifndef HAVE_STRNCASECMPstatic intstrncasecmp(const char *s1, const char *s2, size_t n){	int c1, c2;	while (n > 0) {		c1 = (unsigned char) *s1++;		c2 = (unsigned char) *s2++;		if (c1 == 0)			return -c2;		if (c2 == 0)			return c1;		if (c1 != c2 && tolower(c1) != tolower(c2))			return tolower(c1) - tolower(c2);		n--;	}	return 0;}#endif/* Parse a number and store in a bignum_t.   1 is returned if all is well;   2 is returned if there is loss of precision (i.e. overflow of the value);   0 is returned if the string is not a number, or if scale doesn't fit.*/static intparseint(const char *data, bignum_t *nval){	int fraction = 0;	/* inside the fractional part */	int scale = 0;	int overflow = 0;	nval->val = 0;	nval->precision = 0;	scale = 0;	while (space(*data))		data++;	if (*data == '-') {		nval->sign = 0;		data++;	} else {		nval->sign = 1;		if (*data == '+')			data++;	}	while (*data && *data != 'e' && *data != 'E' && !space(*data)) {		if (*data == '.')			fraction = 1;		else if ('0' <= *data && *data <= '9') {			if (overflow || nval->val > MAXBIGNUM10 || (nval->val == MAXBIGNUM10 && *data > MAXBIGNUMLAST)) {				overflow = 1;				if (!fraction)					scale--;			} else {				nval->precision++;				if (fraction)					scale++;				nval->val *= 10;				nval->val += *data - '0';			}		} else			return 0;		data++;	}	/* normalize scale */	while (scale > 0 && nval->val % 10 == 0) {		scale--;		nval->val /= 10;	}	if (*data == 'e' || *data == 'E') {		char *p;		long i;		i = strtol(data, &p, 10);		if (p == data || *p)			return 0;		scale -= i;		/* normalize scale */		while (scale > 0 && nval->val % 10 == 0) {			scale--;			nval->val /= 10;		}		while (scale < 0 && nval->val <= MAXBIGNUM10) {			scale++;			nval->val *= 10;		}	}	if (scale < -128 || scale > 127)		return 0;	nval->scale = scale;	while (space(*data))		data++;	if (*data)		return 0;	return 1 + overflow;}static intparsesecondinterval(bignum_t *nval, SQL_INTERVAL_STRUCT *ival, int type){	unsigned int f = 1;	int ivalscale = 0;	/* convert value to second */	switch (type) {	case SQL_INTERVAL_DAY:	/* SQL_C_INTERVAL_DAY */		nval->val *= 24;	case SQL_INTERVAL_HOUR: /* SQL_C_INTERVAL_HOUR */	case SQL_INTERVAL_DAY_TO_HOUR: /* SQL_C_INTERVAL_DAY_TO_HOUR */		nval->val *= 60;	case SQL_INTERVAL_MINUTE: /* SQL_C_INTERVAL_MINUTE */	case SQL_INTERVAL_HOUR_TO_MINUTE: /* SQL_C_INTERVAL_HOUR_TO_MINUTE */	case SQL_INTERVAL_DAY_TO_MINUTE: /* SQL_C_INTERVAL_DAY_TO_MINUTE */		nval->val *= 60;	case SQL_INTERVAL_SECOND: /* SQL_C_INTERVAL_SECOND */	case SQL_INTERVAL_MINUTE_TO_SECOND: /* SQL_C_INTERVAL_MINUTE_TO_SECOND */	case SQL_INTERVAL_HOUR_TO_SECOND: /* SQL_C_INTERVAL_HOUR_TO_SECOND */	case SQL_INTERVAL_DAY_TO_SECOND: /* SQL_C_INTERVAL_DAY_TO_SECOND */		break;	default:		assert(0);	}	ival->intval.day_second.fraction = 0;	while (nval->scale > 0) {		if (f < 1000000000) {			ivalscale++;			ival->intval.day_second.fraction += (SQLUINTEGER) ((nval->val % 10) * f);			f *= 10;		}		nval->val /= 10;		nval->scale--;	}	/* normalize scale */	while (ivalscale > 0 && ival->intval.day_second.fraction % 10 != 0) {		ivalscale--;		ival->intval.day_second.fraction /= 10;	}	ival->interval_type = SQL_IS_DAY_TO_SECOND;	ival->interval_sign = !nval->sign;	ival->intval.day_second.second = (SQLUINTEGER) (nval->val % 60);	nval->val /= 60;	ival->intval.day_second.minute = (SQLUINTEGER) (nval->val % 60);	nval->val /= 60;	ival->intval.day_second.hour = (SQLUINTEGER) (nval->val % 24);	nval->val /= 24;	ival->intval.day_second.day = (SQLUINTEGER) nval->val;	return ivalscale;}static voidparsemonthinterval(bignum_t *nval, SQL_INTERVAL_STRUCT *ival, int type){	/* convert value to months */	switch (type) {	case SQL_INTERVAL_YEAR: /* SQL_C_INTERVAL_YEAR */		nval->val *= 12;	case SQL_INTERVAL_YEAR_TO_MONTH: /* SQL_C_INTERVAL_YEAR_TO_MONTH */	case SQL_INTERVAL_MONTH: /* SQL_C_INTERVAL_MONTH */		break;	default:		assert(0);	}	/* ignore fraction */	while (nval->scale > 0) {		nval->scale--;		nval->val /= 10;	}	ival->interval_type = SQL_IS_YEAR_TO_MONTH;	ival->interval_sign = !nval->sign;	ival->intval.year_month.year = (SQLUINTEGER) (nval->val / 12);	ival->intval.year_month.month = (SQLUINTEGER) (nval->val % 12);}static short monthlengths[] = {	0,			/* dummy */	31,			/* Jan */	29,			/* Feb */	31,			/* Mar */	30,			/* Apr */	31,			/* May */	30,			/* Jun */	31,			/* Jul */	31,			/* Aug */	30,			/* Sep */	31,			/* Oct */	30,			/* Nov */	31,			/* Dec */};#define isLeap(y)	((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))static intparsedate(const char *data, DATE_STRUCT *dval){	int n;	while (space(*data))		data++;	if (sscanf(data, "{d '%hd-%hu-%hu'}%n", &dval->year, &dval->month, &dval->day, &n) < 3 &&	    sscanf(data, "%hd-%hu-%hu%n", &dval->year, &dval->month, &dval->day, &n) < 3)		return 0;	if (dval->month == 0 || dval->month > 12 || dval->day == 0 || dval->day > monthlengths[dval->month] || (dval->month == 2 && !isLeap(dval->year) && dval->day == 29))		return 0;	data += n;	while (space(*data))		data++;	if (*data)		return 0;	return 1;}static intparsetime(const char *data, TIME_STRUCT *tval){	int n;	int braces;	while (space(*data))		data++;	if (sscanf(data, "{t '%hu:%hu:%hu%n", &tval->hour, &tval->minute, &tval->second, &n) < 3 &&	    sscanf(data, "%hu:%hu:%hu%n", &tval->hour, &tval->minute, &tval->second, &n) < 3)		return 0;	/* seconds can go up to 61(!) because of leap seconds */	if (tval->hour > 23 || tval->minute > 59 || tval->second > 61)		return 0;	braces = *data == '{';	data += n;	n = 1;			/* tentative return value */	if (*data == '.') {		while (*++data && '0' <= *data && *data <= '9')			;		n = 2;		/* indicate loss of precision */	}	if (braces && *data++ != '\'' && *data++ != '}')		return 0;	while (space(*data))		data++;	if (*data)		return 0;	return n;}static intparsetimestamp(const char *data, TIMESTAMP_STRUCT *tsval){	int n;	int braces;	while (space(*data))		data++;	if (sscanf(data, "{TS '%hd-%hu-%hu %hu:%hu:%hu%n", &tsval->year, &tsval->month, &tsval->day, &tsval->hour, &tsval->minute, &tsval->second, &n) < 6 &&	    sscanf(data, "%hd-%hu-%hu %hu:%hu:%hu%n", &tsval->year, &tsval->month, &tsval->day, &tsval->hour, &tsval->minute, &tsval->second, &n) < 6)		return 0;	if (tsval->month == 0 || tsval->month > 12 || tsval->day == 0 || tsval->day > monthlengths[tsval->month] || (tsval->month == 2 && !isLeap(tsval->year) && tsval->day == 29) || tsval->hour > 23 || tsval->minute > 59 || tsval->second > 61)		return 0;	braces = *data == '{';	tsval->fraction = 0;	data += n;	n = 1000000000;	if (*data == '.') {		while (*++data && '0' <= *data && *data <= '9') {			n /= 10;			tsval->fraction += (*data - '0') * n;		}	}	if (braces && *data++ != '\'' && *data++ != '}')		return 0;	while (space(*data))		data++;	if (*data)		return 0;	if (n == 0)		return 2;	/* fractional digits truncated */	return 1;}static intparsedouble(const char *data, double *fval){	char *p;	while (space(*data))		data++;	errno = 0;	*fval = strtod(data, &p);	if (p == NULL || p == data || errno == ERANGE)		return 0;	while (space(*p))		p++;	if (*p)		return 0;	return 1;}static SQLSMALLINTODBCDefaultType(ODBCDescRec *rec){	switch (rec->sql_desc_concise_type) {	case SQL_CHAR:	case SQL_VARCHAR:	case SQL_LONGVARCHAR:	case SQL_DECIMAL:	case SQL_NUMERIC:		return SQL_C_CHAR;#ifdef WITH_WCHAR	case SQL_WCHAR:	case SQL_WVARCHAR:	case SQL_WLONGVARCHAR:		return SQL_C_WCHAR;#endif	case SQL_BIT:		return SQL_C_BIT;	case SQL_TINYINT:		return rec->sql_desc_unsigned ? SQL_C_UTINYINT : SQL_C_STINYINT;	case SQL_SMALLINT:		return rec->sql_desc_unsigned ? SQL_C_USHORT : SQL_C_SSHORT;	case SQL_INTEGER:		return rec->sql_desc_unsigned ? SQL_C_ULONG : SQL_C_SLONG;	case SQL_BIGINT:		return rec->sql_desc_unsigned ? SQL_C_UBIGINT : SQL_C_SBIGINT;	case SQL_REAL:		return SQL_C_FLOAT;	case SQL_FLOAT:	case SQL_DOUBLE:		return SQL_C_DOUBLE;	case SQL_BINARY:	case SQL_VARBINARY:	case SQL_LONGVARBINARY:		return SQL_C_BINARY;	case SQL_TYPE_DATE:		return SQL_C_TYPE_DATE;	case SQL_TYPE_TIME:		return SQL_C_TYPE_TIME;	case SQL_TYPE_TIMESTAMP:		return SQL_C_TYPE_TIMESTAMP;	case SQL_INTERVAL_YEAR:		return SQL_C_INTERVAL_YEAR;	case SQL_INTERVAL_MONTH:		return SQL_C_INTERVAL_MONTH;	case SQL_INTERVAL_YEAR_TO_MONTH:		return SQL_C_INTERVAL_YEAR_TO_MONTH;	case SQL_INTERVAL_DAY:		return SQL_C_INTERVAL_DAY;	case SQL_INTERVAL_HOUR:		return SQL_C_INTERVAL_HOUR;	case SQL_INTERVAL_MINUTE:		return SQL_C_INTERVAL_MINUTE;	case SQL_INTERVAL_SECOND:		return SQL_C_INTERVAL_SECOND;	case SQL_INTERVAL_DAY_TO_HOUR:		return SQL_C_INTERVAL_DAY_TO_HOUR;	case SQL_INTERVAL_DAY_TO_MINUTE:		return SQL_C_INTERVAL_DAY_TO_MINUTE;	case SQL_INTERVAL_DAY_TO_SECOND:		return SQL_C_INTERVAL_DAY_TO_SECOND;	case SQL_INTERVAL_HOUR_TO_MINUTE:		return SQL_C_INTERVAL_HOUR_TO_MINUTE;	case SQL_INTERVAL_HOUR_TO_SECOND:		return SQL_C_INTERVAL_HOUR_TO_SECOND;	case SQL_INTERVAL_MINUTE_TO_SECOND:		return SQL_C_INTERVAL_MINUTE_TO_SECOND;	case SQL_GUID:		return SQL_C_GUID;	}	return 0;}static SQLRETURNparseoptionalbracketednumber(char **svalp, SQLINTEGER *slenp, int *val1p, int *val2p){	char *sval = *svalp;	int slen = *slenp;	char *eptr;	long val;	while (slen > 0 && isspace((int) *sval)) {		slen--;		sval++;	}	if (slen == 0 || *sval != '(') {		/* don't touch *valp, it contains the default */		return SQL_SUCCESS;	}	slen--;	sval++;	while (slen > 0 && isspace((int) *sval)) {		slen--;		sval++;	}	/* make sure there is a closing parenthesis in the string:	   this makes the calls to strtol safe */	{		int i;		for (eptr = sval, i = slen; i > 0 && *eptr != ')'; i--, eptr++)			;		if (i == 0)			return SQL_ERROR;	}	if (slen > 0 && (*sval == '+' || *sval == '-'))		return SQL_ERROR;	val = strtol(sval, &eptr, 10);	if (eptr == sval)		return SQL_ERROR;	slen -= (int) (eptr - sval);	sval = eptr;	*val1p = (int) val;	while (slen > 0 && isspace((int) *sval)) {		slen--;		sval++;	}	if (val2p != NULL && slen > 0 && *sval == ',') {		slen--;		sval++;		while (slen > 0 && isspace((int) *sval)) {			slen--;			sval++;		}		if (slen > 0 && (*sval == '+' || *sval == '-'))			return SQL_ERROR;		val = strtol(sval, &eptr, 10);		if (eptr == sval)			return SQL_ERROR;		slen -= (int) (eptr - sval);		sval = eptr;		*val2p = val;	}			if (slen == 0 || *sval != ')')

⌨️ 快捷键说明

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