📄 convert.c
字号:
return sizeof(TDS_REAL); break; case SYBFLT8: cr->f = the_value; return sizeof(TDS_FLOAT); break; case SYBNUMERIC: case SYBDECIMAL: sprintf(tmp_str,"%.15g", the_value); return stringz_to_numeric(tmp_str, cr); break; /* not allowed */ case SYBUNIQUE: case SYBDATETIME4: case SYBDATETIME: case SYBDATETIMN: default: return TDS_CONVERT_NOAVAIL; break; }#ifndef NCBI_FTDS return TDS_CONVERT_FAIL;#endif}static TDS_INTtds_convert_unique(int srctype, const TDS_CHAR *src, TDS_INT srclen, int desttype, CONV_RESULT *cr){/* Raw data is equivalent to structure and always aligned, so this cast is portable */const TDS_UNIQUE *u = (const TDS_UNIQUE *) src;char buf[37]; switch(desttype) { case SYBCHAR: case SYBTEXT: case SYBVARCHAR: sprintf(buf,"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", (int)u->Data1,(int)u->Data2,(int)u->Data3, u->Data4[0], u->Data4[1], u->Data4[2], u->Data4[3], u->Data4[4], u->Data4[5], u->Data4[6], u->Data4[7]); return string_to_result(buf,cr); break; case SYBBINARY: case SYBIMAGE: case SYBVARBINARY: return binary_to_result(src,sizeof(TDS_UNIQUE),cr); break; case SYBUNIQUE: /* Here we can copy raw to structure because we adjust byte order in tds_swap_datatype */ memcpy (&(cr->u), src, sizeof(TDS_UNIQUE)); return sizeof(TDS_UNIQUE); break; /* no not warning for not convertible types */ case SYBBIT: case SYBBITN: case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBMONEY4: case SYBMONEY: case SYBDATETIME4: case SYBDATETIME: case SYBDATETIMN: case SYBREAL: case SYBFLT8: default: return TDS_CONVERT_NOAVAIL; break; }#ifndef NCBI_FTDS return TDS_CONVERT_FAIL;#endif}/** * tds_convert * convert a type to another. * If you convert to SYBDECIMAL/SYBNUMERIC you MUST initialize precision * and scale of cr. * Do not expect string to be zero terminated. Databases support zero inside * string. Doing strlen on result may result on data loss or even core. * Use memcpy to copy destination using length returned. * This function do not handle NULL, srclen should be >0, if not undefinited * behaviour... * @param tds_ctx context (used in conversion to data and to return messages) * @param srctype type of source * @param src pointer to source data to convert * @param srclen length in bytes of source (not counting terminator or strings) * @param desttype type of destination * @param cr structure to hold result * @return length of result or TDS_CONVERT_* failure code on failure. All TDS_CONVERT_* constants are <0. */TDS_INT tds_convert(TDSCONTEXT *tds_ctx, int srctype, const TDS_CHAR *src, TDS_UINT srclen, int desttype, CONV_RESULT *cr){TDS_INT length = 0; switch (srctype) { case SYBCHAR: case SYBVARCHAR: case SYBTEXT: length = tds_convert_char(srctype, src, srclen, desttype, cr); break; case SYBMONEY4: length = tds_convert_money4(srctype,src, srclen, desttype, cr); break; case SYBMONEY: length = tds_convert_money(srctype, src, desttype, cr); break; case SYBNUMERIC: case SYBDECIMAL: length = tds_convert_numeric(srctype, (const TDS_NUMERIC *) src, srclen, desttype, cr); break; case SYBBIT: case SYBBITN: length = tds_convert_bit(srctype, src, desttype, cr); break; case SYBINT1: length = tds_convert_int1(srctype, src, desttype, cr); break; case SYBINT2: length = tds_convert_int2(srctype, src, desttype, cr); break; case SYBINT4: length = tds_convert_int4(srctype, src, desttype, cr); break; case SYBINT8: length = tds_convert_int8(srctype, src, desttype, cr); break; case SYBREAL: length = tds_convert_real(srctype, src, desttype, cr); break; case SYBFLT8: length = tds_convert_flt8(srctype, src, desttype, cr); break; case SYBDATETIME: length = tds_convert_datetime(tds_ctx, srctype, src, desttype, cr); break; case SYBDATETIME4: length = tds_convert_datetime4(tds_ctx, srctype, src, desttype, cr); break; case SYBIMAGE: case SYBBINARY: case SYBVARBINARY: length = tds_convert_binary(srctype, (const TDS_UCHAR *) src, srclen, desttype, cr); break; case SYBUNIQUE: length = tds_convert_unique(srctype, src, srclen, desttype, cr); break; case SYBNVARCHAR: case SYBNTEXT: default: return TDS_CONVERT_NOAVAIL; break; }/* fix MONEY case */#if !defined(WORDS_BIGENDIAN) && defined(HAVE_INT64) if (length > 0 && desttype == SYBMONEY) { cr->m.mny = ((TDS_UINT8)cr->m.mny) >> 32 | (cr->m.mny << 32); }#endif return length;}static int string_to_datetime(const char *instr, int desttype, CONV_RESULT *cr){enum states { GOING_IN_BLIND, PUT_NUMERIC_IN_CONTEXT, DOING_ALPHABETIC_DATE, STRING_GARBLED };char *in;char *tok;char *lasts;char last_token[32];int monthdone = 0;int yeardone = 0;int mdaydone = 0;struct tds_time mytime;struct tds_time *t;unsigned int dt_time;TDS_INT dt_days;int i;int current_state; memset(&mytime, '\0', sizeof(struct tds_time)); t = &mytime; in = (char *)malloc(strlen(instr)+1); test_alloc(in); strcpy (in , instr ); tok = strtok_r(in, " ,", &lasts); current_state = GOING_IN_BLIND; while (tok != (char *) NULL) { switch (current_state) { case GOING_IN_BLIND : /* If we have no idea of current context, then if we have */ /* encountered a purely alphabetic string, it MUST be an */ /* alphabetic month name or prefix... */ if (is_alphabetic(tok)) { if (is_monthname(tok)) { store_monthname(tok, t); monthdone++; current_state = DOING_ALPHABETIC_DATE; } else { current_state = STRING_GARBLED; } } /* ...whereas if it is numeric, it could be a number of */ /* things... */ else if (is_numeric(tok)) { switch(strlen(tok)) { /* in this context a 4 character numeric can */ /* ONLY be the year part of an alphabetic date */ case 4: store_year(atoi(tok), t); yeardone++; current_state = DOING_ALPHABETIC_DATE; break; /* whereas these could be the hour part of a */ /* time specification ( 4 PM ) or the leading */ /* day part of an alphabetic date ( 15 Jan ) */ case 2: case 1: strcpy(last_token, tok); current_state = PUT_NUMERIC_IN_CONTEXT; break; /* this must be a [YY]YYMMDD date */ case 6: case 8: if (store_yymmdd_date(tok, t)) current_state = GOING_IN_BLIND; else current_state = STRING_GARBLED; break; /* anything else is nonsense... */ default: current_state = STRING_GARBLED; break; } } /* it could be [M]M/[D]D/[YY]YY format */ else if (is_numeric_dateformat(tok)) { store_numeric_date(tok, t); current_state = GOING_IN_BLIND; } else if (is_timeformat(tok)) { store_time(tok, t); current_state = GOING_IN_BLIND; } else { current_state = STRING_GARBLED; } break; /* end of GOING_IN_BLIND */ case DOING_ALPHABETIC_DATE: if (is_alphabetic(tok)) { if (!monthdone && is_monthname(tok)) { store_monthname(tok, t); monthdone++; if (monthdone && yeardone && mdaydone ) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } else { current_state = STRING_GARBLED; } } else if (is_numeric(tok)) { if (mdaydone && yeardone) current_state = STRING_GARBLED; else switch(strlen(tok)) { case 4: store_year(atoi(tok), t); yeardone++; if (monthdone && yeardone && mdaydone ) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; break; case 2: case 1: if (!mdaydone) { store_mday(tok, t); mdaydone++; if (monthdone && yeardone && mdaydone ) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } else { store_year(atoi(tok), t); yeardone++; if (monthdone && yeardone && mdaydone ) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } break; default: current_state = STRING_GARBLED; } } else { current_state = STRING_GARBLED; } break; /* end of DOING_ALPHABETIC_DATE */ case PUT_NUMERIC_IN_CONTEXT: if (is_alphabetic(tok)) { if (is_monthname(tok)) { store_mday(last_token, t); mdaydone++; store_monthname(tok, t); monthdone++; if (monthdone && yeardone && mdaydone ) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } else if (is_ampm(tok)) { store_hour(last_token, tok, t); current_state = GOING_IN_BLIND; } else { current_state = STRING_GARBLED; } } else if (is_numeric(tok)) { switch(strlen(tok)) { case 4: case 2: store_mday(last_token, t); mdaydone++; store_year(atoi(tok), t); yeardone++; if (monthdone && yeardone && mdaydone ) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; break; default: current_state = STRING_GARBLED; } } else { current_state = STRING_GARBLED; } break; /* end of PUT_NUMERIC_IN_CONTEXT */ case STRING_GARBLED: tdsdump_log(TDS_DBG_INFO1,"error_handler: Attempt to convert data stopped by syntax error in source field \n"); return TDS_CONVERT_SYNTAX; } tok = strtok_r((char *)NULL, " ,", &lasts); } i = (t->tm_mon - 13) / 12; dt_days = 1461 * ( t->tm_year + 300 + i ) / 4 + (367 * ( t->tm_mon - 1 - 12*i ) ) / 12 - (3 * ( ( t->tm_year + 400 + i ) / 100 ) ) / 4 + t->tm_mday - 109544; free(in); /* TODO check for overflow */ if ( desttype == SYBDATETIME ) { cr->dt.dtdays = dt_days; dt_time = (t->tm_hour * 60 + t->tm_min ) * 60 + t->tm_sec; cr->dt.dttime = dt_time * 300 + (t->tm_ms * 300 / 1000); return sizeof(TDS_DATETIME); } else { /* SYBDATETIME4 */ cr->dt4.days = dt_days; cr->dt4.minutes = t->tm_hour * 60 + t->tm_min; return sizeof(TDS_DATETIME4); }}static int stringz_to_numeric(const char *instr, CONV_RESULT *cr){ return string_to_numeric(instr,instr+strlen(instr),cr);}static int string_to_numeric(const char *instr, const char *pend, CONV_RESULT *cr){char mynumber[(MAXPRECISION+7)/8*8];/* num packaged 8 digit, see below for detail */TDS_UINT packed_num[TDS_VECTOR_SIZE(mynumber)/8];char *ptr;const char *pdigits;const char* pstr;TDS_UINT carry = 0;char not_zero = 1;int i = 0;int j = 0;short int bytes, places, point_found, sign, digits; sign = 0; point_found = 0; places = 0; /* FIXME: application can pass invalid value for precision and scale ?? */ if (cr->n.precision > 77) return TDS_CONVERT_FAIL; if (cr->n.precision == 0) cr->n.precision = 77; /* assume max precision */ if ( cr->n.scale > cr->n.precision ) return TDS_CONVERT_FAIL; /* skip leading blanks */ for (pstr = instr;; ++pstr) { if (pstr == pend) return TDS_CONVERT_SYNTAX; if (*pstr != ' ') break; } if ( *pstr == '-' || *pstr == '+' ) /* deal with a leading sign */ { if (*pstr == '-') sign = 1; pstr++; } digits = 0; pdigits = pstr; for(; pstr != pend; ++pstr) /* deal with the rest */ { if (isdigit((unsigned char) *pstr)) /* its a number */ { if (point_found) /* if we passed a decimal point */ ++places; /* count digits after that point */ else ++digits; /* count digits before point */ } else if (*pstr == '.') /* found a decimal point */ { if (point_found) /* already had one. return error */ return TDS_CONVERT_SYNTAX; point_found = 1; } else /* first invalid character */ return TDS_CONVERT_SYNTAX; /* return error. */ } /* no digits? no number!*/ if (!digits) return TDS_CONVERT_SYNTAX; /* truncate decimal digits */ if ( places > cr->n.scale) places = cr->n.scale; /* too digits, error */ if ( (digits+cr->n.scale) > cr->n.precision) return TDS_CONVERT_OVERFLOW; /* TODO: this can be optimized in a single step */ /* scale specified, pad out number with zeroes to the scale... */ ptr = mynumber+sizeof(mynumber)-(cr->n.scale-places); memset(ptr,48,cr->n.scale-places); ptr -= places; /* copy number without point */ memcpy(ptr,pdigits+digits+1,places); ptr -= digits; memcpy(ptr,pdigits,digits); memset(mynumber,48,ptr-mynumber); /* transform ASCII string into a numeric array */ for (ptr = mynumber; ptr != mynumber+sizeof(mynumber); ++ptr) *ptr -= 48; /* * Packaged number explanation * I package 8 decimal digit in one number
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -