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