From 99773f6a0a27024ba31edce6e090b14017a04dda Mon Sep 17 00:00:00 2001 From: unknown <venu@myvenu.com> Date: Thu, 23 Jan 2003 22:36:27 -0800 Subject: [PATCH] MYSQL_TIME handling - client Remove get_binary_length Enable the clients to work wih date,time and ts directly with binary protocol --- include/mysql.h | 18 ++ libmysql/libmysql.c | 411 ++++++++++++++++++++++++++++++-------------- 2 files changed, 302 insertions(+), 127 deletions(-) diff --git a/include/mysql.h b/include/mysql.h index 23bcb81f16..612c7c84aa 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -470,6 +470,24 @@ int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con, /* statement state */ enum PREP_STMT_STATE { MY_ST_UNKNOWN, MY_ST_PREPARE, MY_ST_EXECUTE }; +/* + client TIME structure to handle TIME, DATE and TIMESTAMP directly in + binary protocol +*/ +enum mysql_st_timestamp_type { MYSQL_TIMESTAMP_NONE, MYSQL_TIMESTAMP_DATE, + MYSQL_TIMESTAMP_FULL, MYSQL_TIMESTAMP_TIME }; + +typedef struct mysql_st_time +{ + unsigned int year,month,day,hour,minute,second; + unsigned long second_part; + my_bool neg; + + enum mysql_st_timestamp_type time_type; + +} MYSQL_TIME; + + /* bind structure */ typedef struct st_mysql_bind { diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index ebb90f42b4..8559ff4aea 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -115,7 +115,6 @@ static sig_handler pipe_sig_handler(int sig); static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, const char *from, ulong length); static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list); -static unsigned int get_binary_length(uint type); static my_bool org_my_init_done=0; @@ -4056,6 +4055,71 @@ static void store_param_double(NET *net, MYSQL_BIND *param) net->write_pos+= 8; } +static void store_param_time(NET *net, MYSQL_BIND *param) +{ + MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; + char buff[15], *pos; + uint length; + + pos= buff+1; + pos[0]= tm->neg ? 1: 0; + 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= 11; + else if (tm->hour || tm->minute || tm->second || tm->day) + length= 8; + else + length= 0; + buff[0]= (char) length++; + memcpy((char *)net->write_pos, buff, length); + net->write_pos+= length; +} + +static void net_store_datetime(NET *net, MYSQL_TIME *tm) +{ + char buff[12], *pos; + uint length; + + pos= buff+1; + + int2store(pos, tm->year); + 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; + else if (tm->hour || tm->minute || tm->second) + length= 7; + else if (tm->year || tm->month || tm->day) + length= 4; + else + length= 0; + buff[0]= (char) length++; + memcpy((char *)net->write_pos, buff, length); + net->write_pos+= length; +} + +static void store_param_date(NET *net, MYSQL_BIND *param) +{ + MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; + tm->hour= tm->minute= tm->second= 0; + tm->second_part= 0; + net_store_datetime(net, tm); +} + +static void store_param_datetime(NET *net, MYSQL_BIND *param) +{ + MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer; + net_store_datetime(net, tm); +} + static void store_param_str(NET *net, MYSQL_BIND *param) { ulong length= min(*param->length, param->buffer_length); @@ -4110,7 +4174,10 @@ static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param) Either to the length pointer given by the user or param->buffer_length */ if ((my_realloc_str(net, 9 + *param->length))) + { + set_stmt_error(stmt, CR_OUT_OF_MEMORY); DBUG_RETURN(1); + } (*param->store_param_func)(net, param); } DBUG_RETURN(0); @@ -4326,6 +4393,17 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) param->buffer_length= 8; param->store_param_func= store_param_double; break; + case MYSQL_TYPE_TIME: + /* Buffer length ignored for DATE, TIME and DATETIME */ + param->store_param_func= store_param_time; + break; + case MYSQL_TYPE_DATE: + param->store_param_func= store_param_date; + break; + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + param->store_param_func= store_param_datetime; + break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: @@ -4441,24 +4519,91 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, 1 Error (Can't alloc net->buffer) ****************************************************************************/ -/* Return the default binary data length for the common types */ -static unsigned int get_binary_length(uint type) +static void set_zero_time(MYSQL_TIME *tm) { - switch(type) { - case MYSQL_TYPE_TINY: - return 1; - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_YEAR: - return 2; - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_FLOAT: - return 4; - case MYSQL_TYPE_LONGLONG: - case MYSQL_TYPE_DOUBLE: - return 8; - default: + tm->year= tm->month= tm->day= 0; + tm->hour= tm->minute= tm->second= 0; + tm->second_part= 0; + tm->neg= (bool)0; +} + +/* Read TIME from binary packet and return it to MYSQL_TIME */ +static uint read_binary_time(MYSQL_TIME *tm, uchar **pos) +{ + uchar *to; + uint length; + + if (!(length= net_field_length(pos))) + { + set_zero_time(tm); return 0; } + + to= *pos; + tm->second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0; + + tm->day= (ulong) sint4korr(to+1); + tm->hour= (uint) to[5]; + tm->minute= (uint) to[6]; + tm->second= (uint) to[7]; + + tm->year= tm->month= 0; + tm->neg= (bool)to[0]; + return length; +} + +/* Read DATETIME from binary packet and return it to MYSQL_TIME */ +static uint read_binary_datetime(MYSQL_TIME *tm, uchar **pos) +{ + uchar *to; + uint length; + + if (!(length= net_field_length(pos))) + { + set_zero_time(tm); + return 0; + } + + to= *pos; + tm->second_part= (length > 7 ) ? (ulong) sint4korr(to+7): 0; + + if (length > 4) + { + tm->hour= (uint) to[4]; + tm->minute= (uint) to[5]; + tm->second= (uint) to[6]; + } + else + tm->hour= tm->minute= tm->second= 0; + + tm->year= (uint) sint2korr(to); + tm->month= (uint) to[2]; + tm->day= (uint) to[3]; + tm->neg= 0; + return length; +} + +/* Read DATE from binary packet and return it to MYSQL_TIME */ +static uint read_binary_date(MYSQL_TIME *tm, uchar **pos) +{ + uchar *to; + uint length; + + if (!(length= net_field_length(pos))) + { + set_zero_time(tm); + return 0; + } + + to= *pos; + tm->year = (uint) sint2korr(to); + tm->month= (uint) to[2]; + tm->day= (uint) to[3]; + + tm->hour= tm->minute= tm->second= 0; + tm->second_part= 0; + tm->neg= 0; + return length; } /* Convert Numeric to buffer types */ @@ -4595,20 +4740,72 @@ static void send_data_str(MYSQL_BIND *param, char *value, uint length) } } +static void send_data_time(MYSQL_BIND *param, MYSQL_TIME ltime, + uint length) +{ + switch (param->buffer_type) { + + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + { + MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; + + tm->year= ltime.year; + tm->month= ltime.month; + tm->day= ltime.day; + + tm->hour= ltime.hour; + tm->minute= ltime.minute; + tm->second= ltime.second; + + tm->second_part= ltime.second_part; + tm->neg= ltime.neg; + break; + } + default: + { + char buff[25]; + + if (!length) + ltime.time_type= MYSQL_TIMESTAMP_NONE; + switch (ltime.time_type) { + case MYSQL_TIMESTAMP_DATE: + length= my_sprintf(buff,(buff, "%04d-%02d-%02d", ltime.year, + ltime.month,ltime.day)); + break; + case MYSQL_TIMESTAMP_FULL: + length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", + ltime.year,ltime.month,ltime.day, + ltime.hour,ltime.minute,ltime.second)); + break; + case MYSQL_TIMESTAMP_TIME: + length= my_sprintf(buff, (buff, "%02d:%02d:%02d", + ltime.hour,ltime.minute,ltime.second)); + break; + default: + length= 0; + buff[0]='\0'; + } + send_data_str(param, (char *)buff, length); + } + } +} + + /* Fetch data to buffers */ -static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, - uint field_type, uchar **row) +static void fetch_results(MYSQL_BIND *param, uint field_type, uchar **row) { ulong length; - length= (ulong)get_binary_length(field_type); - switch (field_type) { case MYSQL_TYPE_TINY: { uchar value= (uchar) **row; send_data_long(param,(longlong)value); + length= 1; break; } case MYSQL_TYPE_SHORT: @@ -4616,18 +4813,21 @@ static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, { short value= (short)sint2korr(*row); send_data_long(param,(longlong)value); + length= 2; break; } case MYSQL_TYPE_LONG: { int32 value= (int32)sint4korr(*row); send_data_long(param,(int32)value); + length= 4; break; } case MYSQL_TYPE_LONGLONG: { longlong value= (longlong)sint8korr(*row); send_data_long(param,value); + length= 8; break; } case MYSQL_TYPE_FLOAT: @@ -4635,6 +4835,7 @@ static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, float value; float4get(value,*row); send_data_double(param,(double)value); + length= 4; break; } case MYSQL_TYPE_DOUBLE: @@ -4642,115 +4843,35 @@ static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, double value; float8get(value,*row); send_data_double(param,(double)value); + length= 8; 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); + MYSQL_TIME tm; + + length= read_binary_date(&tm,row); + tm.time_type= MYSQL_TIMESTAMP_DATE; + send_data_time(param, tm, 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); + MYSQL_TIME tm; + + length= read_binary_time(&tm, row); + tm.time_type= MYSQL_TIMESTAMP_TIME; + send_data_time(param, tm, length); + break; + } + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + { + MYSQL_TIME tm; + + length= read_binary_datetime(&tm, row); + tm.time_type= MYSQL_TIMESTAMP_FULL; + send_data_time(param, tm, length); break; } default: @@ -4759,7 +4880,6 @@ static my_bool fetch_results(MYSQL_STMT *stmt, MYSQL_BIND *param, break; } *row+= length; - return 0; } static void fetch_result_tinyint(MYSQL_BIND *param, uchar **row) @@ -4805,6 +4925,24 @@ static void fetch_result_double(MYSQL_BIND *param, uchar **row) *row+= 8; } +static void fetch_result_time(MYSQL_BIND *param, uchar **row) +{ + MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; + *row+= read_binary_time(tm, row); +} + +static void fetch_result_date(MYSQL_BIND *param, uchar **row) +{ + MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; + *row+= read_binary_date(tm, row); +} + +static void fetch_result_datetime(MYSQL_BIND *param, uchar **row) +{ + MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer; + *row+= read_binary_datetime(tm, row); +} + static void fetch_result_str(MYSQL_BIND *param, uchar **row) { ulong length= net_field_length(row); @@ -4853,25 +4991,47 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) if (!param->is_null) param->is_null= &int_is_null_dummy; + if (!param->length) + param->length= ¶m->buffer_length; + /* Setup data copy functions for the different supported types */ switch (param->buffer_type) { case MYSQL_TYPE_TINY: param->fetch_result= fetch_result_tinyint; + *param->length= 1; break; case MYSQL_TYPE_SHORT: param->fetch_result= fetch_result_short; + *param->length= 2; break; case MYSQL_TYPE_LONG: param->fetch_result= fetch_result_int32; + *param->length= 4; break; case MYSQL_TYPE_LONGLONG: param->fetch_result= fetch_result_int64; + *param->length= 8; break; case MYSQL_TYPE_FLOAT: param->fetch_result= fetch_result_float; + *param->length= 4; break; case MYSQL_TYPE_DOUBLE: param->fetch_result= fetch_result_double; + *param->length= 8; + break; + case MYSQL_TYPE_TIME: + param->fetch_result= fetch_result_time; + *param->length= sizeof(MYSQL_TIME); + break; + case MYSQL_TYPE_DATE: + param->fetch_result= fetch_result_date; + *param->length= sizeof(MYSQL_TIME); + break; + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + param->fetch_result= fetch_result_datetime; + *param->length= sizeof(MYSQL_TIME); break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: @@ -4888,9 +5048,6 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) param->buffer_type, param->param_number); DBUG_RETURN(1); } - if (!param->length) - param->length= ¶m->buffer_length; - *param->length= (long)get_binary_length(param->buffer_type); } stmt->res_buffers= 1; DBUG_RETURN(0); @@ -4927,8 +5084,8 @@ static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row) *bind->is_null= 0; if (field->type == bind->buffer_type) (*bind->fetch_result)(bind, &row); - else if (fetch_results(stmt, bind, field->type, &row)) - return 1; + else + fetch_results(bind, field->type, &row); } if (! ((bit<<=1) & 255)) { -- 2.30.9