diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index d6d2dca9af0..9d87cef2e34 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1739,7 +1739,6 @@ static void mysql_once_init() #define strdup_if_not_null(A) (A) == 0 ? 0 : my_strdup((A),MYF(MY_WME)) -#ifdef HAVE_OPENSSL my_bool STDCALL mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , const char *key __attribute__((unused)), @@ -1748,14 +1747,15 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) , const char *capath __attribute__((unused)), const char *cipher __attribute__((unused))) { +#ifdef HAVE_OPENSSL mysql->options.ssl_key= strdup_if_not_null(key); mysql->options.ssl_cert= strdup_if_not_null(cert); mysql->options.ssl_ca= strdup_if_not_null(ca); mysql->options.ssl_capath= strdup_if_not_null(capath); mysql->options.ssl_cipher= strdup_if_not_null(cipher); +#endif /* HAVE_OPENSSL */ return 0; } -#endif /************************************************************************** @@ -3927,27 +3927,8 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length) /* Returns prepared meta information in the form of resultset to client. -TODO : Return param information also */ -MYSQL_RES *prepare_result(MYSQL_FIELD *fields, unsigned long count) -{ - MYSQL_RES *result; - - if (!count || !fields) - return 0; - - if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+ - sizeof(ulong)*count, - MYF(MY_WME | MY_ZEROFILL)))) - return 0; - - result->eof=1; /* Marker for buffered */ - result->fields= fields; - result->field_count= count; - return result; -} - MYSQL_RES * STDCALL mysql_prepare_result(MYSQL_STMT *stmt) { @@ -4430,6 +4411,327 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, ****************************************************************************/ +static ulong get_field_length(uint type) +{ + ulong length; + + switch (type) { + + case MYSQL_TYPE_TINY: + length= 1; + break; + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_YEAR: + length= 2; + break; + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + length= 4; + break; + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_DOUBLE: + length= 8; + break; + default: + length= 0; + } + return length; +} + +static void send_data_long(MYSQL_BIND *param, longlong value) +{ + char *buffer= param->buffer; + + *param->length= get_field_length(param->buffer_type); + switch(param->buffer_type) { + + case MYSQL_TYPE_TINY: + *param->buffer= (uchar) value; + break; + case MYSQL_TYPE_SHORT: + int2store(buffer, (short)value); + break; + case MYSQL_TYPE_LONG: + int4store(buffer, (int32)value); + break; + case MYSQL_TYPE_LONGLONG: + int8store(buffer, (longlong)value); + break; + case MYSQL_TYPE_FLOAT: + { + float data= (float)value; + float4store(buffer, data); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double data= (double)value; + float8store(buffer, data); + break; + } + default: + { + uint length= sprintf(buffer,"%lld",value); + *param->length= length; + buffer[length]='\0'; + } + } +} + +static void send_data_double(MYSQL_BIND *param, double value) +{ + char *buffer= param->buffer; + + *param->length= get_field_length(param->buffer_type); + switch(param->buffer_type) { + + case MYSQL_TYPE_TINY: + *buffer= (uchar)value; + break; + case MYSQL_TYPE_SHORT: + int2store(buffer, (short)value); + break; + case MYSQL_TYPE_LONG: + int4store(buffer, (int32)value); + break; + case MYSQL_TYPE_LONGLONG: + int8store(buffer, (longlong)value); + break; + case MYSQL_TYPE_FLOAT: + { + float data= (float)value; + float4store(buffer, data); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double data= (double)value; + float8store(buffer, data); + break; + } + default: + { + uint length= sprintf(buffer,"%g",value); + *param->length= length; + buffer[length]='\0'; + } + } +} + +static void send_data_str(MYSQL_BIND *param, char *value, uint src_length) +{ + char *buffer= param->buffer; + + *param->length= get_field_length(param->buffer_type); + switch(param->buffer_type) { + + case MYSQL_TYPE_TINY: + *buffer= (char)*value; + break; + case MYSQL_TYPE_SHORT: + { + short data= (short)sint2korr(value); + int2store(buffer, data); + break; + } + case MYSQL_TYPE_LONG: + { + int32 data= (int32)sint4korr(value); + int4store(buffer, data); + break; + } + case MYSQL_TYPE_LONGLONG: + { + longlong data= sint8korr(value); + int8store(buffer, data); + break; + } + case MYSQL_TYPE_FLOAT: + { + float data; + float4get(data, value); + float4store(buffer, data); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double data; + float8get(data, value); + float8store(buffer, data); + break; + } + default: + *param->length= src_length; + memcpy(buffer, value, src_length); + buffer[src_length]='\0'; + } +} + +static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, + uint field_type, uchar **row) +{ + ulong length; + + length= get_field_length(field_type); + switch (field_type) { + + case MYSQL_TYPE_TINY: + { + uchar value= (uchar) **row; + send_data_long(param,(longlong)value); + break; + } + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_YEAR: + { + short value= (short)sint2korr(*row); + send_data_long(param,(longlong)value); + break; + } + case MYSQL_TYPE_LONG: + { + int32 value= (int32)sint4korr(*row); + send_data_long(param,(int32)value); + break; + } + case MYSQL_TYPE_LONGLONG: + { + longlong value= (longlong)sint8korr(*row); + send_data_long(param,value); + break; + } + case MYSQL_TYPE_FLOAT: + { + float value; + float4get(value,*row); + send_data_double(param,(double)value); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double value; + float8get(value,*row); + send_data_double(param,(double)value); + break; + } + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + { + uchar month,day; + short year; + int arg_length; + char ts[50],frac[10],time[20],date[20]; + + if (!(length= net_field_length(row))) + { + *param->length= 0; + break; + } + if (param->buffer_type < MYSQL_TYPE_VAR_STRING || + param->buffer_type > MYSQL_TYPE_STRING) + { + /* + Don't allow fetching of date/time/ts to non-string types + TODO: Allow fetching of date or time to long types. + */ + sprintf(stmt->last_error, + ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), + param->buffer_type, param->param_number); + return 1; + } + + arg_length= 0; + if (length > 7) + { + int sec_part= sint4korr(*row+7); + sprintf(frac,".%04d", sec_part); + arg_length+= 5; + } + if (length == 7) + { + uchar hour, minute, sec; + hour= *(*row+4); + minute= *(*row+5); + sec= *(*row+6); + sprintf((char *)time," %02d:%02d:%02d",hour,minute,sec); + arg_length+= 9; + } + + year= sint2korr(*row); + month= *(*row+2); + day= *(*row+3); + sprintf((char*) date,"%04d-%02d-%02d",year,month,day); + arg_length+= 10; + + if (arg_length != 19) + time[0]='\0'; + if (arg_length != 24) + frac[0]='\0'; + + strxmov(ts,date,time,frac,NullS); + send_data_str(param,ts,arg_length); + break; + } + case MYSQL_TYPE_TIME: + { + int day, arg_length; + uchar hour, minute, sec; + char ts[255], frac[20], time[20]; + const char *sign= ""; + + if (!(length= net_field_length(row))) + { + *param->length= 0; + break; + } + if (param->buffer_type < MYSQL_TYPE_VAR_STRING || + param->buffer_type > MYSQL_TYPE_STRING) + { + /* + Don't allow fetching of date/time/ts to non-string types + + TODO: Allow fetching of time to long types without + any conversion. + */ + sprintf(stmt->last_error, + ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE), + param->buffer_type, param->param_number); + return 1; + } + arg_length= 0; + if (length > 8) + { + int sec_part= sint4korr(*row+8); + sprintf(frac,".%04d", sec_part); + arg_length+= 5; + } + + if (**row) + sign="-"; + + day= sint4korr(*row); /* TODO: how to handle this case */ + hour= *(*row+5); + minute= *(*row+6); + sec= *(*row+7); + arg_length+= sprintf((char *)time,"%s%02d:%02d:%02d",sign,hour,minute,sec); + + if (arg_length <= 9) + frac[0]='\0'; + + strxmov(ts,time,frac,NullS); + send_data_str(param,ts,arg_length); + break; + } + default: + length= net_field_length(row); + send_data_str(param,*row,length); + break; + } + *row+= length; + return 0; +} + static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row) { *param->buffer= (uchar) **row; @@ -4438,23 +4740,23 @@ static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row) static void fetch_result_short(MYSQL_BIND *param, uchar **row) { - short value= (short)**row; - int2store(param->buffer, value); - *row+=2; + short value = (short)sint2korr(*row); + int2store(param->buffer, value); + *row+= 2; } static void fetch_result_int32(MYSQL_BIND *param, uchar **row) { - int32 value= (int32)**row; + int32 value= (int32)sint4korr(*row); int4store(param->buffer, value); - *row+=4; + *row+= 4; } static void fetch_result_int64(MYSQL_BIND *param, uchar **row) -{ - longlong value= (longlong)**row; +{ + longlong value= (longlong)sint8korr(*row); int8store(param->buffer, value); - *row+=8; + *row+= 8; } static void fetch_result_float(MYSQL_BIND *param, uchar **row) @@ -4462,7 +4764,7 @@ static void fetch_result_float(MYSQL_BIND *param, uchar **row) float value; float4get(value,*row); float4store(param->buffer, value); - *row+=4; + *row+= 4; } static void fetch_result_double(MYSQL_BIND *param, uchar **row) @@ -4470,16 +4772,16 @@ static void fetch_result_double(MYSQL_BIND *param, uchar **row) double value; float8get(value,*row); float8store(param->buffer, value); - *row+=8; + *row+= 8; } static void fetch_result_str(MYSQL_BIND *param, uchar **row) { ulong length= net_field_length(row); memcpy(param->buffer, (char *)*row, length); - *(param->buffer+length)= '\0'; /* do we need this for all cases.. I doubt */ + *(param->buffer+length)= '\0'; *param->length= length; - *row+=length; + *row+= length; } /* @@ -4535,9 +4837,10 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: - param->length= ¶m->buffer_length; + param->bind_length= 0; param->fetch_result= fetch_result_str; break; default: @@ -4560,7 +4863,7 @@ static void stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) { MYSQL_BIND *bind, *end; - MYSQL_FIELD *field; + MYSQL_FIELD *field, *field_end; uchar *null_ptr, bit; null_ptr= row; @@ -4569,15 +4872,20 @@ stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) /* Copy complete row to application buffers */ for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count, - field= stmt->fields; - bind < end && field; + field= stmt->fields, + field_end= (MYSQL_FIELD *)stmt->fields+stmt->field_count; + bind < end && field < field_end; bind++, field++) { if (*null_ptr & bit) *bind->length= MYSQL_NULL_DATA; else - /* TODO: Add conversion routines code here */ - (*bind->fetch_result)(bind, &row); + { + if (field->type == bind->buffer_type) + (*bind->fetch_result)(bind, &row); + else if (fetch_results(stmt, bind, field->type, &row)) + break; + } if (! (bit<<=1) & 255) { bit= 1; /* To next byte */ diff --git a/sql/field.cc b/sql/field.cc index 1a0b5d496b2..d3de4e144bf 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3257,9 +3257,7 @@ int Field_year::store(longlong nr) bool Field_year::send_binary(Protocol *protocol) { ulonglong tmp= Field_year::val_int(); - TIME tm; - tm.year= (uint32) tmp; - return protocol->store_date(&tm); + return protocol->store_short(tmp); } double Field_year::val_real(void) diff --git a/sql/protocol.cc b/sql/protocol.cc index 63bca9b70b3..d7cf9d39b5c 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -852,7 +852,8 @@ bool Protocol_prep::store_short(longlong from) { #ifndef DEBUG_OFF DBUG_ASSERT(field_types == 0 || - field_types[field_pos] == MYSQL_TYPE_SHORT); + field_types[field_pos] == MYSQL_TYPE_SHORT || + field_types[field_pos] == MYSQL_TYPE_YEAR); #endif field_pos++; char *to= packet->prep_append(2, PACKET_BUFFET_EXTRA_ALLOC); @@ -939,7 +940,6 @@ bool Protocol_prep::store(TIME *tm) { #ifndef DEBUG_OFF DBUG_ASSERT(field_types == 0 || - field_types[field_pos] == MYSQL_TYPE_YEAR || field_types[field_pos] == MYSQL_TYPE_DATETIME || field_types[field_pos] == MYSQL_TYPE_DATE || field_types[field_pos] == MYSQL_TYPE_TIMESTAMP); @@ -950,11 +950,11 @@ bool Protocol_prep::store(TIME *tm) pos= buff+1; int2store(pos, tm->year); - int2store(pos+2, tm->month); - int2store(pos+3, tm->day); - int2store(pos+4, tm->hour); - int2store(pos+5, tm->minute); - int2store(pos+6, tm->second); + pos[2]= (uchar) tm->month; + pos[3]= (uchar) tm->day; + pos[4]= (uchar) tm->hour; + pos[5]= (uchar) tm->minute; + pos[6]= (uchar) tm->second; int4store(pos+7, tm->second_part); if (tm->second_part) length=11; @@ -987,15 +987,15 @@ bool Protocol_prep::store_time(TIME *tm) field_pos++; pos= buff+1; pos[0]= tm->neg ? 1 : 0; - int4store(pos+1, tm->day); - int2store(pos+5, tm->hour); - int2store(pos+7, tm->minute); - int2store(pos+9, tm->second); - int4store(pos+11, tm->second_part); + int4store(pos+1, tm->day); + pos[5]= (uchar) tm->hour; + pos[6]= (uchar) tm->minute; + pos[7]= (uchar) tm->second; + int4store(pos+8, tm->second_part); if (tm->second_part) - length=14; + length=11; else if (tm->hour || tm->minute || tm->second || tm->day) - length=10; + length=8; else length=0; buff[0]=(char) length; // Length is stored first