diff options
Diffstat (limited to 'sql/field_conv.cc')
-rw-r--r-- | sql/field_conv.cc | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/sql/field_conv.cc b/sql/field_conv.cc new file mode 100644 index 00000000000..aae9f18e6a0 --- /dev/null +++ b/sql/field_conv.cc @@ -0,0 +1,528 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +/* + Functions to copy data to or from fields + This could be done with a single short function but opencooding this + gives much more speed. + */ + +#include "mysql_priv.h" +#include <m_ctype.h> + +static void do_field_eq(Copy_field *copy) +{ + memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); +} + +static void do_field_1(Copy_field *copy) +{ + copy->to_ptr[0]=copy->from_ptr[0]; +} + +static void do_field_2(Copy_field *copy) +{ + copy->to_ptr[0]=copy->from_ptr[0]; + copy->to_ptr[1]=copy->from_ptr[1]; +} + +static void do_field_3(Copy_field *copy) +{ + copy->to_ptr[0]=copy->from_ptr[0]; + copy->to_ptr[1]=copy->from_ptr[1]; + copy->to_ptr[2]=copy->from_ptr[2]; +} + +static void do_field_4(Copy_field *copy) +{ + copy->to_ptr[0]=copy->from_ptr[0]; + copy->to_ptr[1]=copy->from_ptr[1]; + copy->to_ptr[2]=copy->from_ptr[2]; + copy->to_ptr[3]=copy->from_ptr[3]; +} + +static void do_field_6(Copy_field *copy) +{ // For blob field + copy->to_ptr[0]=copy->from_ptr[0]; + copy->to_ptr[1]=copy->from_ptr[1]; + copy->to_ptr[2]=copy->from_ptr[2]; + copy->to_ptr[3]=copy->from_ptr[3]; + copy->to_ptr[4]=copy->from_ptr[4]; + copy->to_ptr[5]=copy->from_ptr[5]; +} + +static void do_field_8(Copy_field *copy) +{ + copy->to_ptr[0]=copy->from_ptr[0]; + copy->to_ptr[1]=copy->from_ptr[1]; + copy->to_ptr[2]=copy->from_ptr[2]; + copy->to_ptr[3]=copy->from_ptr[3]; + copy->to_ptr[4]=copy->from_ptr[4]; + copy->to_ptr[5]=copy->from_ptr[5]; + copy->to_ptr[6]=copy->from_ptr[6]; + copy->to_ptr[7]=copy->from_ptr[7]; +} + + +static void do_field_to_null_str(Copy_field *copy) +{ + if (*copy->from_null_ptr & copy->from_bit) + { + bzero(copy->to_ptr,copy->from_length); + copy->to_null_ptr[0]=1; // Always bit 1 + } + else + { + copy->to_null_ptr[0]=0; + memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); + } +} + + +static void do_outer_field_to_null_str(Copy_field *copy) +{ + if (*copy->null_row || + copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)) + { + bzero(copy->to_ptr,copy->from_length); + copy->to_null_ptr[0]=1; // Always bit 1 + } + else + { + copy->to_null_ptr[0]=0; + memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); + } +} + + +bool +set_field_to_null(Field *field) +{ + if (field->maybe_null()) + { + field->set_null(); + field->reset(); + } + else + { + if (field->type() == FIELD_TYPE_TIMESTAMP) + { + ((Field_timestamp*) field)->set_time(); + return 0; // Ok to set time to NULL + } + field->reset(); + if (field == field->table->next_number_field) + return 0; // field is set in handler.cc + if (current_thd->count_cuted_fields) + { + current_thd->cuted_fields++; // Increment error counter + return 0; + } + if (!current_thd->no_errors) + my_printf_error(ER_BAD_NULL_ERROR,ER(ER_BAD_NULL_ERROR),MYF(0),field->field_name); + return 1; + } + return 0; +} + + +static void do_skip(Copy_field *copy __attribute__((unused))) +{ +} + + +static void do_copy_null(Copy_field *copy) +{ + if (*copy->from_null_ptr & copy->from_bit) + { + *copy->to_null_ptr|=copy->to_bit; + copy->to_field->reset(); + } + else + { + *copy->to_null_ptr&= ~copy->to_bit; + (copy->do_copy2)(copy); + } +} + + +static void do_outer_field_null(Copy_field *copy) +{ + if (*copy->null_row || + copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)) + { + *copy->to_null_ptr|=copy->to_bit; + copy->to_field->reset(); + } + else + { + *copy->to_null_ptr&= ~copy->to_bit; + (copy->do_copy2)(copy); + } +} + + +static void do_copy_not_null(Copy_field *copy) +{ + if (*copy->from_null_ptr & copy->from_bit) + { + current_thd->cuted_fields++; + copy->to_field->reset(); + } + else + (copy->do_copy2)(copy); +} + + +static void do_copy_maybe_null(Copy_field *copy) +{ + *copy->to_null_ptr&= ~copy->to_bit; + (copy->do_copy2)(copy); +} + +/* timestamp and next_number has special handling in case of NULL values */ + +static void do_copy_timestamp(Copy_field *copy) +{ + if (*copy->from_null_ptr & copy->from_bit) + { + ((Field_timestamp*) copy->to_field)->set_time();// Same as set_field_to_null + } + else + (copy->do_copy2)(copy); +} + + +static void do_copy_next_number(Copy_field *copy) +{ + if (*copy->from_null_ptr & copy->from_bit) + copy->to_field->reset(); // Same as set_field_to_null + else + (copy->do_copy2)(copy); +} + + +static void do_copy_blob(Copy_field *copy) +{ + ulong length=((Field_blob*) copy->from_field)->get_length(); + ((Field_blob*) copy->to_field)->store_length(length); + memcpy_fixed(copy->to_ptr,copy->from_ptr,sizeof(char*)); +} + +static void do_conv_blob(Copy_field *copy) +{ + copy->from_field->val_str(©->tmp,©->tmp); + ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(), + copy->tmp.length()); +} + +/* Save blob in copy->tmp for GROUP BY */ + +static void do_save_blob(Copy_field *copy) +{ + char buff[MAX_FIELD_WIDTH]; + String res(buff,sizeof(buff)); + copy->from_field->val_str(&res,&res); + copy->tmp.copy(res); + ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(), + copy->tmp.length()); +} + + +static void do_field_string(Copy_field *copy) +{ + char buff[MAX_FIELD_WIDTH]; + copy->tmp.set_quick(buff,sizeof(buff)); + copy->from_field->val_str(©->tmp,©->tmp); + copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length()); +} + + +static void do_field_int(Copy_field *copy) +{ + longlong value=copy->from_field->val_int(); + copy->to_field->store(value); +} + +static void do_field_real(Copy_field *copy) +{ + double value=copy->from_field->val_real(); + copy->to_field->store(value); +} + + +static void do_cut_string(Copy_field *copy) +{ // Shorter string field + memcpy(copy->to_ptr,copy->from_ptr,copy->to_length); + + /* Check if we loosed any important characters */ + char *ptr,*end; + for (ptr=copy->from_ptr+copy->to_length,end=copy->from_ptr+copy->from_length ; + ptr != end ; + ptr++) + { + if (!isspace(*ptr)) + { + current_thd->cuted_fields++; // Give a warning + break; + } + } +} + + +static void do_expand_string(Copy_field *copy) +{ + memcpy(copy->to_ptr,copy->from_ptr,copy->from_length); + bfill(copy->to_ptr+copy->from_length,copy->to_length-copy->from_length,' '); +} + +static void do_varstring(Copy_field *copy) +{ + uint length=uint2korr(copy->from_ptr); + if (length > copy->to_length-2) + { + length=copy->to_length-2; + if (current_thd->count_cuted_fields) + current_thd->cuted_fields++; // Increment error counter + } + int2store(copy->to_ptr,length); + memcpy(copy->to_ptr+2, copy->from_ptr,length); +} + +/*************************************************************************** +** The different functions that fills in a Copy_field class +***************************************************************************/ + +/* + copy of field to maybe null string. + If field is null then the all bytes are set to 0. + if field is not null then the first byte is set to 1 and the rest of the + string is the field value. + The 'to' buffer should have a size of field->pack_length()+1 +*/ + +void Copy_field::set(char *to,Field *from) +{ + from_ptr=from->ptr; + to_ptr=to; + from_length=from->pack_length(); + if (from->maybe_null()) + { + from_null_ptr=from->null_ptr; + from_bit= from->null_bit; + to_ptr[0]= 1; // Null as default value + to_null_ptr= (uchar*) to_ptr++; + to_bit= 1; + if (from->table->maybe_null) + { + null_row= &from->table->null_row; + do_copy= do_outer_field_to_null_str; + } + else + do_copy= do_field_to_null_str; + } + else + { + to_null_ptr= 0; // For easy debugging + do_copy= do_field_eq; + } +} + + + +void Copy_field::set(Field *to,Field *from,bool save) +{ + if (to->type() == FIELD_TYPE_NULL) + { + to_null_ptr=0; // For easy debugging + to_ptr=0; + do_copy=do_skip; + return; + } + from_field=from; + to_field=to; + from_ptr=from->ptr; + from_length=from->pack_length(); + to_ptr= to->ptr; + to_length=to_field->pack_length(); + + // set up null handling + from_null_ptr=to_null_ptr=0; + if (from->maybe_null()) + { + from_null_ptr= from->null_ptr; + from_bit= from->null_bit; + if (to_field->real_maybe_null()) + { + to_null_ptr= to->null_ptr; + to_bit= to->null_bit; + if (from_null_ptr) + do_copy= do_copy_null; + else + { + null_row= &from->table->null_row; + do_copy= do_outer_field_null; + } + } + else + do_copy=do_copy_not_null; + } + else if (to_field->real_maybe_null()) + { + to_null_ptr= to->null_ptr; + to_bit= to->null_bit; + if (to_field->type() == FIELD_TYPE_TIMESTAMP) + do_copy=do_copy_timestamp; // Automatic timestamp + else if (to_field == to_field->table->next_number_field) + do_copy=do_copy_next_number; + else + do_copy=do_copy_maybe_null; + } + else + do_copy=0; + + if ((to->flags & BLOB_FLAG) && save) + do_copy2= do_save_blob; + else + do_copy2= get_copy_func(to,from); + if (!do_copy) // Not null + do_copy=do_copy2; +} + + +void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) +{ + if (to->flags & BLOB_FLAG) + { + if (!(from->flags & BLOB_FLAG)) + return do_conv_blob; + if (from_length != to_length || + to->table->db_low_byte_first != from->table->db_low_byte_first) + { + // Correct pointer to point at char pointer + to_ptr+=to_length - to->table->blob_ptr_size; + from_ptr+=from_length- from->table->blob_ptr_size; + return do_copy_blob; + } + } + else + { + // Check if identical fields + if (from->result_type() == STRING_RESULT) + { + if (to->real_type() != from->real_type() || + to->table->db_low_byte_first != from->table->db_low_byte_first) + { + if (from->real_type() == FIELD_TYPE_ENUM || + from->real_type() == FIELD_TYPE_SET) + if (to->result_type() != STRING_RESULT) + return do_field_int; // Convert SET to number + return do_field_string; + } + if (to->real_type() == FIELD_TYPE_ENUM || + to->real_type() == FIELD_TYPE_SET) + { + if (!to->eq_def(from)) + return do_field_string; + } + else if (to->real_type() == FIELD_TYPE_VAR_STRING && to_length != + from_length) + return do_varstring; + else if (to_length < from_length) + return do_cut_string; + else if (to_length > from_length) + return do_expand_string; + } + else if (to->real_type() != from->real_type() || + to_length != from_length || + to->table->db_low_byte_first != from->table->db_low_byte_first) + { + if (to->real_type() == FIELD_TYPE_DECIMAL || + to->result_type() == STRING_RESULT) + return do_field_string; + if (to->result_type() == INT_RESULT) + return do_field_int; + return do_field_real; + } + else + { + if (!to->eq_def(from) || + to->table->db_low_byte_first != from->table->db_low_byte_first) + { + if (to->real_type() == FIELD_TYPE_DECIMAL) + return do_field_string; + if (to->result_type() == INT_RESULT) + return do_field_int; + else + return do_field_real; + } + } + } + /* Eq fields */ + switch (to_length) { + case 1: return do_field_1; + case 2: return do_field_2; + case 3: return do_field_3; + case 4: return do_field_4; + case 6: return do_field_6; + case 8: return do_field_8; + } + return do_field_eq; +} + + +/* Simple quick field convert that is called on insert */ + +void field_conv(Field *to,Field *from) +{ + if (to->real_type() == from->real_type()) + { + if (to->pack_length() == from->pack_length() && + to->real_type() != FIELD_TYPE_ENUM && + to->real_type() != FIELD_TYPE_SET && + to->table->db_low_byte_first == from->table->db_low_byte_first) + { // Identical fields + memcpy(to->ptr,from->ptr,to->pack_length()); + return; + } + } + if (to->type() == FIELD_TYPE_BLOB) + { // Be sure the value is stored + Field_blob *blob=(Field_blob*) to; + from->val_str(&blob->value,&blob->value); + if (!blob->value.is_alloced() && + from->real_type() != FIELD_TYPE_STRING) + blob->value.copy(); + blob->store(blob->value.ptr(),blob->value.length()); + return; + } + if ((from->result_type() == STRING_RESULT && + (to->result_type() == STRING_RESULT || + (from->real_type() != FIELD_TYPE_ENUM && + from->real_type() != FIELD_TYPE_SET))) || + to->type() == FIELD_TYPE_DECIMAL) + { + char buff[MAX_FIELD_WIDTH]; + String result(buff,sizeof(buff)); + from->val_str(&result,&result); + to->store(result.c_ptr_quick(),result.length()); + } + else if (from->result_type() == REAL_RESULT) + to->store(from->val_real()); + else + to->store(from->val_int()); +} |