in driver/execute.cc [569:815]
SQLRETURN convert_c_type2str(STMT *stmt, SQLSMALLINT ctype, DESCREC *iprec,
char **res, long *length, char *buff, uint buff_max)
{
switch ( ctype )
{
case SQL_C_BINARY:
case SQL_C_CHAR:
break;
case SQL_C_WCHAR:
{
/* Convert SQL_C_WCHAR (utf-16 or utf-32) to utf-8. */
int has_utf8_maxlen4= 0;
/* length is in bytes, we want chars */
*length= *length / sizeof(SQLWCHAR);
*res= (char*)sqlwchar_as_utf8_ext((SQLWCHAR*)*res, (SQLINTEGER*)length,
(SQLCHAR*)buff, buff_max,
&has_utf8_maxlen4);
if (has_utf8_maxlen4 &&
!is_minimum_version(stmt->dbc->connection_proxy->get_server_version(), "5.5.3"))
{
return stmt->set_error("HY000",
"Server does not support 4-byte encoded "
"UTF8 characters.", 0);
}
break;
}
case SQL_C_BIT:
case SQL_C_TINYINT:
case SQL_C_STINYINT:
*length = (long)(my_int2str((long)*((signed char *)*res), buff, -10, 0) - buff);
*res= buff;
break;
case SQL_C_UTINYINT:
*length = (long)(my_int2str((long)*((unsigned char *)*res), buff, -10, 0) - buff);
*res= buff;
break;
case SQL_C_SHORT:
case SQL_C_SSHORT:
*length = (long)(my_int2str((long)*((short int *)*res), buff, -10, 0) - buff);
*res= buff;
break;
case SQL_C_USHORT:
*length = (long)(my_int2str((long)*((unsigned short int *)*res), buff, -10, 0) -
buff);
*res= buff;
break;
case SQL_C_LONG:
case SQL_C_SLONG:
*length = (long)(my_int2str(*((SQLINTEGER*) *res), buff, -10, 0) - buff);
*res= buff;
break;
case SQL_C_ULONG:
*length = (long)(my_int2str(*((SQLUINTEGER*) *res), buff, 10, 0) - buff);
*res= buff;
break;
case SQL_C_SBIGINT:
*length = (long)(myodbc_ll2str(*((longlong*) *res), buff, -10) - buff);
*res= buff;
break;
case SQL_C_UBIGINT:
*length = (long)(myodbc_ll2str(*((ulonglong*) *res), buff, 10) - buff);
*res= buff;
break;
case SQL_C_FLOAT:
if ( iprec->concise_type != SQL_NUMERIC && iprec->concise_type != SQL_DECIMAL )
{
// Better precision
myodbc_d2str(*((float *)*res), buff, buff_max);
}
else
{
// We should perpare this data for string comparison, less precision
myodbc_d2str(*((float *)*res), buff, buff_max, false);
}
*length = (long)strlen(*res= buff);
break;
case SQL_C_DOUBLE:
if ( iprec->concise_type != SQL_NUMERIC && iprec->concise_type != SQL_DECIMAL )
{
myodbc_d2str(*((double *)*res), buff, buff_max);
}
else
{
// We should perpare this data for string comparison, less precision
myodbc_d2str(*((double*)*res), buff, buff_max, false);
}
*length = (long)strlen(*res= buff);
break;
case SQL_C_DATE:
case SQL_C_TYPE_DATE:
{
DATE_STRUCT *date= (DATE_STRUCT*) *res;
if (stmt->dbc->ds->opt_MIN_DATE_TO_ZERO && !date->year
&& (date->month == date->day == 1))
{
*length = myodbc_snprintf(buff, buff_max, "0000-00-00");
}
else
{
*length = myodbc_snprintf(buff, buff_max, "%04d-%02d-%02d",
date->year, date->month, date->day);
}
*res= buff;
break;
}
case SQL_C_TIME:
case SQL_C_TYPE_TIME:
{
TIME_STRUCT *time= (TIME_STRUCT*) *res;
if (time->hour > 23)
{
return stmt->set_error("22008", "Not a valid time value supplied", 0);
}
*length = myodbc_snprintf(buff, buff_max, "%02d:%02d:%02d",
time->hour, time->minute, time->second);
*res= buff;
break;
}
case SQL_C_TIMESTAMP:
case SQL_C_TYPE_TIMESTAMP:
{
TIMESTAMP_STRUCT *time= (TIMESTAMP_STRUCT*) *res;
if (stmt->dbc->ds->opt_MIN_DATE_TO_ZERO &&
!time->year && (time->month == time->day == 1))
{
*length = myodbc_snprintf(buff, buff_max, "0000-00-00 %02d:%02d:%02d",
time->hour, time->minute, time->second);
}
else
{
*length = myodbc_snprintf(buff, buff_max,
"%04d-%02d-%02d %02d:%02d:%02d",
time->year, time->month, time->day,
time->hour, time->minute, time->second);
}
if (time->fraction)
{
char *tmp_buf= buff + *length;
/* Start cleaning from the end */
int tmp_pos= 9;
myodbc_snprintf(tmp_buf, buff_max - *length,
".%09d", time->fraction);
/*
ODBC specification defines nanoseconds granularity for
the fractional part of seconds. MySQL only supports
microseconds for TIMESTAMP, TIME and DATETIME.
We are trying to remove the trailing zeros because this
does not really modify the data, but often helps to substitute
9 digits with only 6.
*/
while (tmp_pos && tmp_buf[tmp_pos] == '0')
{
tmp_buf[tmp_pos--]= 0;
}
*length+= tmp_pos + 1;
}
*res= buff;
break;
}
case SQL_C_NUMERIC:
{
int trunc;
SQL_NUMERIC_STRUCT *sqlnum= (SQL_NUMERIC_STRUCT *) *res;
sqlnum_to_str(sqlnum, (SQLCHAR *)(buff + buff_max - 1),
(SQLCHAR **) res,
(SQLCHAR) iprec->precision,
(SQLSCHAR) iprec->scale, &trunc);
*length = (long)strlen(*res);
/* TODO no way to return an error here? */
if (trunc == SQLNUM_TRUNC_FRAC)
{/* 01S07 SQL_SUCCESS_WITH_INFO */
stmt->set_error("01S07", "Fractional truncation", 0);
return SQL_SUCCESS_WITH_INFO;
}
else if (trunc == SQLNUM_TRUNC_WHOLE)
{/* 22003 SQL_ERROR */
return SQL_ERROR;
}
break;
}
case SQL_C_INTERVAL_HOUR_TO_MINUTE:
case SQL_C_INTERVAL_HOUR_TO_SECOND:
{
SQL_INTERVAL_STRUCT *interval= (SQL_INTERVAL_STRUCT*)*res;
if (ctype == SQL_C_INTERVAL_HOUR_TO_MINUTE)
{
/* Dirty-hackish */
if (ssps_used(stmt))
{
*length = myodbc_snprintf(buff, buff_max, "%d:%02d:00",
interval->intval.day_second.hour,
interval->intval.day_second.minute);
}
else
{
*length = myodbc_snprintf(buff, buff_max, "'%d:%02d:00'",
interval->intval.day_second.hour,
interval->intval.day_second.minute);
}
}
else
{
if (ssps_used(stmt))
{
*length = myodbc_snprintf(buff, buff_max, "%d:%02d:%02d",
interval->intval.day_second.hour,
interval->intval.day_second.minute,
interval->intval.day_second.second);
}
else
{
*length = myodbc_snprintf(buff, buff_max, "'%d:%02d:%02d'",
interval->intval.day_second.hour,
interval->intval.day_second.minute,
interval->intval.day_second.second);
}
}
*res= buff;
break;
}
/* If we are missing processing of some valid C type. Probably means a bug elsewhere */
default:
return stmt->set_error("07006",
"Conversion is not supported", 0);
}
return SQL_SUCCESS;
}