convert.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:77k
- /*
- * ===========================================================================
- * PRODUCTION $Log: convert.c,v $
- * PRODUCTION Revision 1000.1 2003/11/17 22:20:23 gouriano
- * PRODUCTION PRODUCTION: UPGRADED [ORIGINAL] Dev-tree R1.2
- * PRODUCTION
- * ===========================================================================
- */
- /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
- * Copyright (C) 1998-1999 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.
- */
- #include <tds_config.h>
- #include "tdsutil.h"
- #include "tds.h"
- #include "tdsconvert.h"
- # include <time.h>
- #include <assert.h>
- #include <errno.h>
- #ifdef DMALLOC
- #include <dmalloc.h>
- #endif
- #include <string.h>
- #ifndef HAVE_ATOLL
- static long int
- atoll(const char *nptr)
- {
- return atol(nptr);
- }
- #endif
- #ifdef NCBI_FTDS
- extern const int g__numeric_bytes_per_prec[];
- extern char *tds_money_to_string(TDS_MONEY *money, char *s);
- #define TDS_VECTOR_SIZE(x) (sizeof(x)/sizeof(x[0]))
- #endif
- static char software_version[] = "$Id: convert.c,v 1000.1 2003/11/17 22:20:23 gouriano Exp $";
- static void *no_unused_var_warn[] = {software_version,
- no_unused_var_warn};
- 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 );
- #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 IS_INT(x) ( (-2147483647l-1l) <= (x) && (x) <= 2147483647l )
- /**
- * defgroup convert Conversion
- */
- /** 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);
- /**
- * convert a number in string to TDS_INT
- * @return TDS_CONVERT_* failure code if failure
- */
- static TDS_INT string_to_int(const char *buf,const char *pend,TDS_INT* res);
- #define TDS_CONVERT_NOAVAIL -2
- /**
- * convert a number in string to TDS_INT8
- * @return TDS_CONVERT_* failure code if failure
- */
- static TDS_INT string_to_int8(const char *buf,const char *pend,TDS_INT8* res);
- static int store_hour(char *, char *, struct tds_time *);
- static int store_time(char *, struct tds_time * );
- static int store_yymmdd_date(char *, struct tds_time *);
- static int store_monthname(char *, struct tds_time *);
- static int store_numeric_date(char *, struct tds_time *);
- static int store_mday(char *, struct tds_time *);
- static int store_year(int, struct tds_time *);
- /* static int days_this_year (int years); */
- static int is_timeformat(char *);
- static int is_numeric(char *);
- static int is_alphabetic(char *);
- static int is_ampm(char *);
- static int is_monthname(char *);
- static int is_numeric_dateformat(char *);
- #if 0
- static TDS_UINT utf16len(const utf16_t* s);
- static const char *tds_prtype(int token);
- #endif
- /**
- * 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
- */
- int tds_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_conmvert 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_INT
- string_to_result(const char* s,CONV_RESULT* cr)
- {
- int len = strlen(s);
- cr->c = (TDS_CHAR *) malloc(len + 1);
- test_alloc(cr->c);
- memcpy(cr->c, s, len + 1);
- return len;
- }
- /**
- * Copy binary data to to result and return len or TDS_CONVERT_NOMEM
- */
- static TDS_INT
- binary_to_result(const void* data,size_t len,CONV_RESULT* cr)
- {
- cr->ib = (TDS_CHAR *) malloc(len);
- test_alloc(cr->ib);
- memcpy(cr->ib, data, len);
- return len;
- }
- /* 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_INT
- tds_convert_binary(int srctype, const TDS_UCHAR *src, TDS_INT srclen,
- int desttype, CONV_RESULT *cr)
- {
- int cplen;
- int s;
- char *c;
- char hex2[3];
- switch(desttype) {
- case SYBCHAR:
- case SYBVARCHAR:
- case SYBTEXT:
- /* 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++) {
- sprintf(hex2, "%02x", src[s]);
- *c++ = hex2[0];
- *c++ = hex2[1];
- }
- *c = ' ';
- return (srclen * 2);
- break;
- case SYBIMAGE:
- case SYBBINARY:
- case SYBVARBINARY:
- 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 = get_size_by_type(desttype);
- if (cplen <= srclen)
- return binary_to_result(src, cplen, cr);
- cr->ib = (TDS_CHAR *) malloc(cplen);
- test_alloc(cr->ib);
- memcpy(cr->ib, src, srclen);
- memset(cr->ib+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:
- return TDS_CONVERT_NOAVAIL;
- break;
- }
- #ifndef NCBI_FTDS
- return TDS_CONVERT_FAIL;
- #endif
- }
- static TDS_INT
- tds_convert_char(int srctype, const TDS_CHAR *src, TDS_UINT srclen,
- int desttype, CONV_RESULT *cr)
- {
- int i, j;
- unsigned char hex1;
- TDS_INT8 mymoney;
- TDS_INT mymoney4;
- char mynumber[39];
- const char *ptr, *pend;
- int point_found, places;
- TDS_INT tds_i;
- TDS_INT8 tds_i8;
- TDS_INT rc;
-
- switch(desttype) {
- case SYBCHAR:
- case SYBVARCHAR:
- case SYBTEXT:
- cr->c = (TDS_CHAR *) malloc(srclen + 1);
- test_alloc(cr->c);
- memcpy(cr->c, src, srclen);
- cr->c[srclen] = 0;
- return srclen;
- break;
- case SYBBINARY:
- case SYBIMAGE:
- case SYBVARBINARY:
- /* 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] == ' ') )
- --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;
- }
- cr->ib = (TDS_CHAR *) malloc(srclen / 2);
- test_alloc(cr->ib);
- #if 0
- /* hey, I know this looks a bit cruddy, */
- /* and I'm sure it can all be done in one */
- /* statement, so go on, make my day! */
- for ( i = 0, j = 0; i < srclen; i++, j++ ) {
- inp = src[i];
- if ( inp > 47 && inp < 58 ) /* '0' thru '9' */
- hex1 = inp - 48;
- else if ( inp > 96 && inp < 103 ) /* 'a' thru 'f' */
- hex1 = inp - 87;
- else if ( inp > 64 && inp < 71 ) /* 'A' thru 'F' */
- hex1 = inp - 55;
- else {
- fprintf(stderr,"error_handler: Attempt to convert data stopped by syntax error in source field n");
- return;
- }
-
- hex1 = hex1 << 4;
-
- i++;
-
- inp = src[i];
- if ( inp > 47 && inp < 58 ) /* '0' thru '9' */
- hex1 = hex1 | (inp - 48);
- else if ( inp > 96 && inp < 103 ) /* 'a' thru 'f' */
- hex1 = hex1 | (inp - 87);
- else if ( inp > 64 && inp < 71 ) /* 'A' thru 'F' */
- hex1 = hex1 | (inp - 55);
- else {
- fprintf(stderr,"error_handler: Attempt to convert data stopped by syntax error in source field n");
- return;
- }
-
- cr->ib[j] = hex1;
- }
- #else
- 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( i & 1 )
- cr->ib[i/2] = hex1;
- else
- cr->ib[i/2] |= hex1 << 4;
- }
- #endif
- 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:
- cr->f = atof(src);
- return sizeof(TDS_FLOAT);
- break;
- case SYBREAL:
- 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 TDS_CONVERT_OVERFLOW;
- 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);
- memcpy(&(cr->m), &mymoney, sizeof(TDS_MONEY) );
- return sizeof(TDS_MONEY);
- } else {
- mymoney4 = atol(mynumber);
- memcpy(&(cr->m4), &mymoney4, sizeof(TDS_MONEY4) );
- return sizeof(TDS_MONEY4);
- }
- break;
- case SYBDATETIME:
- return string_to_datetime(src, SYBDATETIME, cr);
- break;
- case SYBDATETIME4:
- 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;
- /* parse formats like XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX
- * or {XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}
- * SQL seem to ignore additional character... */
- if (srclen < (32+3)) return TDS_CONVERT_SYNTAX;
- if (src[0] == '{') {
- if (srclen < (32+5) || src[32+4] != '}')
- return TDS_CONVERT_SYNTAX;
- ++src;
- }
- if (src[8] != '-' || src[8+4+1] != '-' || src[16+2] != '-')
- return TDS_CONVERT_SYNTAX;
- /* test all characters and get value
- * first I tried using sscanf but it work if number terminate
- * 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+4+1:
- if (c!='-') return TDS_CONVERT_SYNTAX;
- cr->u.Data2 = n;
- n = 0;
- break;
- case 16+2:
- if (c!='-') return TDS_CONVERT_SYNTAX;
- cr->u.Data3 = n;
- n = 0;
- break;
- default:
- n = n << 4;
- if (c >= '0' && c <= '9') n += c-'0';
- else {
- c &= 0x20 ^ 0xff;
- if (c >= 'A' && c <= 'F')
- n += c-('A'-10);
- else return TDS_CONVERT_SYNTAX;
- }
- if (i>(16+2) && !(i&1)) {
- cr->u.Data4[(i>>1)-10] = n;
- n = 0;
- }
- }
- }
- }
- return sizeof(TDS_UNIQUE);
- default:
- return TDS_CONVERT_NOAVAIL;
- break;
- } /* end switch */
- } /* tds_convert_char */
- static TDS_INT
- tds_convert_bit(int srctype, const TDS_CHAR *src,
- int desttype, CONV_RESULT *cr)
- {
- int canonic = src[0] ? 1 : 0;
- switch(desttype) {
- case SYBCHAR:
- case SYBVARCHAR:
- case SYBTEXT:
- cr->c = (TDS_CHAR *) malloc(2);
- test_alloc(cr->c);
- cr->c[0] = '0' + canonic;
- cr->c[1] = 0;
- return 1;
- break;
- case SYBBINARY:
- case SYBIMAGE:
- case SYBVARBINARY:
- return binary_to_result(src,1,cr);
- break;
- case SYBINT1:
- cr->ti = canonic;
- return sizeof(TDS_TINYINT);
- break;
- case SYBINT2:
- cr->si = canonic;
- return sizeof(TDS_SMALLINT);
- break;
- case SYBINT4:
- cr->i = canonic;
- return sizeof(TDS_INT);
- break;
- case SYBINT8:
- cr->bi = canonic;
- return sizeof(TDS_INT8);
- break;
- case SYBFLT8:
- cr->f = canonic;
- return sizeof(TDS_FLOAT);
- break;
- case SYBREAL:
- cr->r = (TDS_REAL) canonic;
- return sizeof(TDS_REAL);
- break;
- case SYBBIT:
- case SYBBITN:
- cr->ti = src[0];
- return sizeof(TDS_TINYINT);
- break;
- case SYBMONEY:
- case SYBMONEY4:
- return tds_convert_int1( SYBINT1, (src[0])? "1" : "