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 + -
显示快捷键?