convert.c

来自「postgresql-odbc,跨平台应用」· C语言 代码 · 共 2,560 行 · 第 1/5 页

C
2,560
字号
/*------- * Module:				 convert.c * * Description:    This module contains routines related to *				   converting parameters and columns into requested data types. *				   Parameters are converted from their SQL_C data types into *				   the appropriate postgres type.  Columns are converted from *				   their postgres type (SQL type) into the appropriate SQL_C *				   data type. * * Classes:		   n/a * * API functions:  none * * Comments:	   See "notice.txt" for copyright and license information. *------- *//* Multibyte support  Eiji Tokuya	2001-03-15	*/#include "convert.h"#ifdef	WIN32#include <float.h>#endif /* WIN32 */#include <stdio.h>#include <string.h>#include <ctype.h>#include "multibyte.h"#include <time.h>#ifdef HAVE_LOCALE_H#include <locale.h>#endif#include <math.h>#include <stdlib.h>#include "statement.h"#include "qresult.h"#include "bind.h"#include "pgtypes.h"#include "lobj.h"#include "connection.h"#include "catfunc.h"#include "pgapifunc.h"#if defined(UNICODE_SUPPORT) && defined(WIN32)#define	WIN_UNICODE_SUPPORT#endifCSTR	NAN_STRING = "NaN";CSTR	INFINITY_STRING = "Infinity";CSTR	MINFINITY_STRING = "-Infinity";#ifdef	__CYGWIN__#define TIMEZONE_GLOBAL _timezone#elif	defined(WIN32) || defined(HAVE_INT_TIMEZONE)#define TIMEZONE_GLOBAL timezone#endif/* *	How to map ODBC scalar functions {fn func(args)} to Postgres. *	This is just a simple substitution.  List augmented from: *	http://www.merant.com/datadirect/download/docs/odbc16/Odbcref/rappc.htm *	- thomas 2000-04-03 */char	   *mapFuncs[][2] = {/*	{ "ASCII",		 "ascii"	  }, built_in */	{"CHAR", "chr($*)" },	{"CONCAT", "textcat($*)" },/*	{ "DIFFERENCE", "difference" }, how to ? */	{"INSERT", "substring($1 from 1 for $2 - 1) || $4 || substring($1 from $2 + $3)" },	{"LCASE", "lower($*)" },	{"LEFT", "ltrunc($*)" },	{"%2LOCATE", "strpos($2,  $1)" },	/* 2 parameters */	{"%3LOCATE", "strpos(substring($2 from $3), $1) + $3 - 1" },	/* 3 parameters */	{"LENGTH", "char_length($*)"},/*	{ "LTRIM",		 "ltrim"	  }, built_in */	{"RIGHT", "rtrunc($*)" },	{"SPACE", "repeat('' '', $1)" },/*	{ "REPEAT",		 "repeat"	  }, built_in *//*	{ "REPLACE", "replace" }, ??? *//*	{ "RTRIM",		 "rtrim"	  }, built_in *//*	{ "SOUNDEX", "soundex" }, how to ? */	{"SUBSTRING", "substr($*)" },	{"UCASE", "upper($*)" },/*	{ "ABS",		 "abs"		  }, built_in *//*	{ "ACOS",		 "acos"		  }, built_in *//*	{ "ASIN",		 "asin"		  }, built_in *//*	{ "ATAN",		 "atan"		  }, built_in *//*	{ "ATAN2",		 "atan2"	  }, bui;t_in */	{"CEILING", "ceil($*)" },/*	{ "COS",		 "cos" 		  }, built_in *//*	{ "COT",		 "cot" 		  }, built_in *//*	{ "DEGREES",		 "degrees" 	  }, built_in *//*	{ "EXP",		 "exp" 		  }, built_in *//*	{ "FLOOR",		 "floor" 	  }, built_in */	{"LOG", "ln($*)" },	{"LOG10", "log($*)" },/*	{ "MOD",		 "mod" 		  }, built_in *//*	{ "PI",			 "pi" 		  }, built_in */	{"POWER", "pow($*)" },/*	{ "RADIANS",		 "radians"	  }, built_in */	{"%0RAND", "random()" },	/* 0 parameters */	{"%1RAND", "(setseed($1) * .0 + random())" },	/* 1 parameters *//*	{ "ROUND",		 "round"	  }, built_in *//*	{ "SIGN",		 "sign"		  }, built_in *//*	{ "SIN",		 "sin"		  }, built_in *//*	{ "SQRT",		 "sqrt"		  }, built_in *//*	{ "TAN",		 "tan"		  }, built_in */	{"TRUNCATE", "trunc($*)" },	{"CURRENT_DATE", "current_date" },	{"CURRENT_TIME", "current_time" },	{"CURRENT_TIMESTAMP", "current_timestamp" },	{"LOCALTIME", "localtime" },	{"LOCALTIMESTAMP", "localtimestamp" },	{"CURRENT_USER", "cast(current_user as text)" },	{"SESSION_USER", "cast(session_user as text)" },	{"CURDATE",	 "current_date" },	{"CURTIME",	 "current_time" },	{"DAYNAME",	 "to_char($1, 'Day')" },	{"DAYOFMONTH",  "cast(extract(day from $1) as integer)" },	{"DAYOFWEEK",	 "(cast(extract(dow from $1) as integer) + 1)" },	{"DAYOFYEAR",	 "cast(extract(doy from $1) as integer)" }, 	{"HOUR",	 "cast(extract(hour from $1) as integer)" },	{"MINUTE",	"cast(extract(minute from $1) as integer)" },	{"MONTH",	"cast(extract(month from $1) as integer)" },	{"MONTHNAME",	 " to_char($1, 'Month')" },/*	{ "NOW",		 "now"		  }, built_in */	{"QUARTER",	 "cast(extract(quarter from $1) as integer)" },	{"SECOND",	"cast(extract(second from $1) as integer)" },	{"WEEK",	"cast(extract(week from $1) as integer)" },	{"YEAR",	"cast(extract(year from $1) as integer)" },/*	{ "DATABASE",	 "database"   }, */	{"IFNULL", "coalesce($*)" },	{"USER", "cast(current_user as text)" },	{0, 0}};static const char *mapFunction(const char *func, int param_count);static int conv_from_octal(const UCHAR *s);static SQLLEN pg_bin2hex(UCHAR *src, UCHAR *dst, SQLLEN length);/*--------- *			A Guide for date/time/timestamp conversions * *			field_type		fCType				Output *			----------		------				---------- *			PG_TYPE_DATE	SQL_C_DEFAULT		SQL_C_DATE *			PG_TYPE_DATE	SQL_C_DATE			SQL_C_DATE *			PG_TYPE_DATE	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(time = 0 (midnight)) *			PG_TYPE_TIME	SQL_C_DEFAULT		SQL_C_TIME *			PG_TYPE_TIME	SQL_C_TIME			SQL_C_TIME *			PG_TYPE_TIME	SQL_C_TIMESTAMP		SQL_C_TIMESTAMP		(date = current date) *			PG_TYPE_ABSTIME SQL_C_DEFAULT		SQL_C_TIMESTAMP *			PG_TYPE_ABSTIME SQL_C_DATE			SQL_C_DATE			(time is truncated) *			PG_TYPE_ABSTIME SQL_C_TIME			SQL_C_TIME			(date is truncated) *			PG_TYPE_ABSTIME SQL_C_TIMESTAMP		SQL_C_TIMESTAMP *--------- *//* *	Macros for unsigned long handling. */#ifdef	WIN32#define	ATOI32U	atol#elif	defined(HAVE_STRTOUL)#define	ATOI32U(val)	strtoul(val, NULL, 10)#else /* HAVE_STRTOUL */#define	ATOI32U	atol#endif /* WIN32 *//* *	Macros for BIGINT handling. */#ifdef	ODBCINT64#ifdef	WIN32#define	ATOI64	_atoi64#define	ATOI64U	_atoi64#define	FORMATI64	"%I64d"#define	FORMATI64U	"%I64u"#elif	(SIZEOF_LONG == 8)#define	ATOI64(val)	strtol(val, NULL, 10)#define	ATOI64U(val)	strtoul(val, NULL, 10)#define	FORMATI64	"%ld"#define	FORMATI64U	"%lu"#else#define	FORMATI64	"%lld"#define	FORMATI64U	"%llu"#if	defined(HAVE_STRTOLL)#define	ATOI64(val)	strtoll(val, NULL, 10)#define	ATOI64U(val)	strtoull(val, NULL, 10)#elsestatic ODBCINT64 ATOI64(const char *val){	ODBCINT64 ll;	sscanf(val, "%lld", &ll);	return ll;}static unsigned ODBCINT64 ATOI64U(const char *val){	unsigned ODBCINT64 ll;	sscanf(val, "%llu", &ll);	return ll;}#endif /* HAVE_STRTOLL */#endif /* WIN32 */#endif /* ODBCINT64 *//* *	TIMESTAMP <-----> SIMPLE_TIME *		precision support since 7.2. *		time zone support is unavailable(the stuff is unreliable) */static BOOLtimestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone){	char		rest[64], bc[16],			   *ptr;	int			scnt,				i;#ifdef	TIMEZONE_GLOBAL	long		timediff;#endif	BOOL		withZone = *bZone;	*bZone = FALSE;	*zone = 0;	st->fr = 0;	st->infinity = 0;	rest[0] = '\0';	bc[0] = '\0';	if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%32s %16s", &st->y, &st->m, &st->d, &st->hh, &st->mm, &st->ss, rest, bc)) < 6)		return FALSE;	else if (scnt == 6)		return TRUE;	switch (rest[0])	{		case '+':			*bZone = TRUE;			*zone = atoi(&rest[1]);			break;		case '-':			*bZone = TRUE;			*zone = -atoi(&rest[1]);			break;		case '.':			if ((ptr = strchr(rest, '+')) != NULL)			{				*bZone = TRUE;				*zone = atoi(&ptr[1]);				*ptr = '\0';			}			else if ((ptr = strchr(rest, '-')) != NULL)			{				*bZone = TRUE;				*zone = -atoi(&ptr[1]);				*ptr = '\0';			}			for (i = 1; i < 10; i++)			{				if (!isdigit((UCHAR) rest[i]))					break;			}			for (; i < 10; i++)				rest[i] = '0';			rest[i] = '\0';			st->fr = atoi(&rest[1]);			break;		case 'B':			if (stricmp(rest, "BC") == 0)				st->y *= -1;			return TRUE;		default:			return TRUE;	}	if (stricmp(bc, "BC") == 0)	{		st->y *= -1;	}	if (!withZone || !*bZone || st->y < 1970)		return TRUE;#ifdef	TIMEZONE_GLOBAL	if (!tzname[0] || !tzname[0][0])	{		*bZone = FALSE;		return TRUE;	}	timediff = TIMEZONE_GLOBAL + (*zone) * 3600;	if (!daylight && timediff == 0)		/* the same timezone */		return TRUE;	else	{		struct tm	tm,				   *tm2;		time_t		time0;		*bZone = FALSE;		tm.tm_year = st->y - 1900;		tm.tm_mon = st->m - 1;		tm.tm_mday = st->d;		tm.tm_hour = st->hh;		tm.tm_min = st->mm;		tm.tm_sec = st->ss;		tm.tm_isdst = -1;		time0 = mktime(&tm);		if (time0 < 0)			return TRUE;		if (tm.tm_isdst > 0)			timediff -= 3600;		if (timediff == 0)		/* the same time zone */			return TRUE;		time0 -= timediff;#ifdef	HAVE_LOCALTIME_R		if (time0 >= 0 && (tm2 = localtime_r(&time0, &tm)) != NULL)#else		if (time0 >= 0 && (tm2 = localtime(&time0)) != NULL)#endif /* HAVE_LOCALTIME_R */		{			st->y = tm2->tm_year + 1900;			st->m = tm2->tm_mon + 1;			st->d = tm2->tm_mday;			st->hh = tm2->tm_hour;			st->mm = tm2->tm_min;			st->ss = tm2->tm_sec;			*bZone = TRUE;		}	}#endif /* TIMEZONE_GLOBAL */	return TRUE;}static BOOLstime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, BOOL precision){	char		precstr[16],				zonestr[16];	int			i;	precstr[0] = '\0';	if (st->infinity > 0)	{		strcpy(str, INFINITY_STRING);		return TRUE;	}	else if (st->infinity < 0)	{		strcpy(str, MINFINITY_STRING);		return TRUE;	}	if (precision && st->fr)	{		sprintf(precstr, ".%09d", st->fr);		for (i = 9; i > 0; i--)		{			if (precstr[i] != '0')				break;			precstr[i] = '\0';		}	}	zonestr[0] = '\0';#ifdef	TIMEZONE_GLOBAL	if (bZone && tzname[0] && tzname[0][0] && st->y >= 1970)	{		long		zoneint;		struct tm	tm;		time_t		time0;		zoneint = TIMEZONE_GLOBAL;		if (daylight && st->y >= 1900)		{			tm.tm_year = st->y - 1900;			tm.tm_mon = st->m - 1;			tm.tm_mday = st->d;			tm.tm_hour = st->hh;			tm.tm_min = st->mm;			tm.tm_sec = st->ss;			tm.tm_isdst = -1;			time0 = mktime(&tm);			if (time0 >= 0 && tm.tm_isdst > 0)				zoneint -= 3600;		}		if (zoneint > 0)			sprintf(zonestr, "-%02d", (int) zoneint / 3600);		else			sprintf(zonestr, "+%02d", -(int) zoneint / 3600);	}#endif /* TIMEZONE_GLOBAL */	if (st->y < 0)		sprintf(str, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s BC", -st->y, st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr);	else		sprintf(str, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s", st->y, st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr);	return TRUE;}/*	This is called by SQLFetch() */intcopy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, void *value, int col){	ARDFields *opts = SC_get_ARDF(stmt);	BindInfoClass *bic = &(opts->bindings[col]);	SQLULEN	offset = opts->row_offset_ptr ? *opts->row_offset_ptr : 0;	SC_set_current_col(stmt, -1);	return copy_and_convert_field(stmt, field_type, value, bic->returntype,			(PTR) (bic->buffer + offset), bic->buflen,			LENADDR_SHIFT(bic->used, offset), LENADDR_SHIFT(bic->indicator, offset));}static double get_double_value(const char *str){	if (stricmp(str, NAN_STRING) == 0)#ifdef	NAN		return (double) NAN;#else	{		double	a = .0;		return .0 / a;	}#endif /* NAN */	else if (stricmp(str, INFINITY_STRING) == 0)#ifdef	INFINITY		return (double) INFINITY;#else		return (double) (HUGE_VAL * HUGE_VAL);#endif /* INFINITY */	else if (stricmp(str, MINFINITY_STRING) == 0)#ifdef	INFINITY		return (double) -INFINITY;#else		return (double) -(HUGE_VAL * HUGE_VAL);#endif /* INFINITY */	return atof(str);}/*	This is called by SQLGetData() */intcopy_and_convert_field(StatementClass *stmt, OID field_type, void *valuei,			SQLSMALLINT fCType, PTR rgbValue, SQLLEN cbValueMax,			SQLLEN *pcbValue, SQLLEN *pIndicator){	CSTR func = "copy_and_convert_field";	const char *value = valuei;	ARDFields	*opts = SC_get_ARDF(stmt);	GetDataInfo	*gdata = SC_get_GDTI(stmt);	SQLLEN		len = 0,				copy_len = 0, needbuflen = 0;	SIMPLE_TIME std_time;	time_t		stmt_t = SC_get_time(stmt);	struct tm  *tim;#ifdef	HAVE_LOCALTIME_R	struct tm  tm;#endif /* HAVE_LOCALTIME_R */	SQLLEN			pcbValueOffset,				rgbValueOffset;	char	   *rgbValueBindRow = NULL;	SQLLEN		*pcbValueBindRow = NULL, *pIndicatorBindRow = NULL;	const char *ptr;	SQLSETPOSIROW		bind_row = stmt->bind_row;	int			bind_size = opts->bind_size;	int			result = COPY_OK;	ConnectionClass		*conn = SC_get_conn(stmt);	BOOL		changed, true_is_minus1 = FALSE;	BOOL	text_handling, localize_needed;	const char *neut_str = value;	char		midtemp[2][32];	int			mtemp_cnt = 0;	GetDataClass *pgdc;#ifdef	UNICODE_SUPPORT	BOOL	wconverted =   FALSE;#endif /* UNICODE_SUPPORT */#ifdef	WIN_UNICODE_SUPPORT	SQLWCHAR	*allocbuf = NULL;	ssize_t		wstrlen;	#endif /* WIN_UNICODE_SUPPORT */#ifdef HAVE_LOCALE_H	char *saved_locale;#endif /* HAVE_LOCALE_H */	if (stmt->current_col >= 0)	{		if (stmt->current_col >= opts->allocated)		{			return SQL_ERROR;		}		if (gdata->allocated != opts->allocated)			extend_getdata_info(gdata, opts->allocated, TRUE);		pgdc = &gdata->gdata[stmt->current_col];		if (pgdc->data_left == -2)			pgdc->data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be *						 * needed by ADO ? */		if (pgdc->data_left == 0)		{			if (pgdc->ttlbuf != NULL)			{				free(pgdc->ttlbuf);				pgdc->ttlbuf = NULL;				pgdc->ttlbuflen = 0;			}			pgdc->data_left = -2;		/* needed by ADO ? */			return COPY_NO_DATA_FOUND;		}	}	/*---------	 *	rgbValueOffset is *ONLY* for character and binary data.	 *	pcbValueOffset is for computing any pcbValue location	 *---------	 */

⌨️ 快捷键说明

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