diff options
author | unknown <pem@mysql.com> | 2004-04-07 19:07:44 +0200 |
---|---|---|
committer | unknown <pem@mysql.com> | 2004-04-07 19:07:44 +0200 |
commit | c635d37479fbf8aa0da03d47f264ab9907cfe72b (patch) | |
tree | e5ac1517ff3dccc42352b7bac39ecd1c093d0ae6 /sql/field.cc | |
parent | 8468cde4f1e028b380c24d0bac28402678568d81 (diff) | |
parent | 0948f9769b3e3da2e064e65015b86644af4acd78 (diff) | |
download | mariadb-git-c635d37479fbf8aa0da03d47f264ab9907cfe72b.tar.gz |
Merge 4.1 -> 5.0.
BitKeeper/etc/ignore:
auto-union
BitKeeper/etc/logging_ok:
auto-union
VC++Files/sql/mysqld.dsp:
Auto merged
client/Makefile.am:
Auto merged
client/mysql.cc:
Auto merged
client/mysqltest.c:
Auto merged
configure.in:
Auto merged
include/my_global.h:
Auto merged
include/my_pthread.h:
Auto merged
include/my_sys.h:
Auto merged
include/mysql_com.h:
Auto merged
libmysqld/Makefile.am:
Auto merged
libmysqld/lib_sql.cc:
Auto merged
myisam/mi_check.c:
Auto merged
myisam/myisamchk.c:
Auto merged
myisam/myisamdef.h:
Auto merged
mysql-test/install_test_db.sh:
Auto merged
mysql-test/r/insert_select.result:
Auto merged
mysql-test/r/join_outer.result:
Auto merged
mysql-test/r/null.result:
Auto merged
mysql-test/r/connect.result:
Auto merged
mysql-test/r/func_sapdb.result:
Auto merged
mysql-test/r/mix_innodb_myisam_binlog.result:
Auto merged
mysql-test/r/mysqldump.result:
Auto merged
mysql-test/r/rpl_change_master.result:
Auto merged
mysql-test/r/rpl_log.result:
Auto merged
mysql-test/r/show_check.result:
Auto merged
mysql-test/r/symlink.result:
Auto merged
mysql-test/r/rpl_flush_log_loop.result:
Auto merged
mysql-test/r/rpl_flush_tables.result:
Auto merged
mysql-test/r/rpl_loaddata.result:
Auto merged
mysql-test/r/rpl_loaddata_rule_m.result:
Auto merged
mysql-test/r/rpl_loaddata_rule_s.result:
Auto merged
mysql-test/r/rpl_max_relay_size.result:
Auto merged
mysql-test/r/rpl_reset_slave.result:
Auto merged
mysql-test/r/rpl_temporary.result:
Auto merged
mysql-test/r/rpl_until.result:
Auto merged
mysql-test/r/rpl_user_variables.result:
Auto merged
mysql-test/r/subselect.result:
Auto merged
mysql-test/r/union.result:
Auto merged
mysql-test/r/variables.result:
Auto merged
mysql-test/t/func_sapdb.test:
Auto merged
mysql-test/t/mix_innodb_myisam_binlog.test:
Auto merged
mysql-test/t/mysqlbinlog.test:
Auto merged
mysql-test/t/rpl_change_master.test:
Auto merged
mysql-test/t/rpl_log.test:
Auto merged
mysql-test/t/variables.test:
Auto merged
netware/BUILD/compile-linux-tools:
Auto merged
netware/BUILD/compile-netware-END:
Auto merged
netware/BUILD/compile-netware-all:
Auto merged
netware/BUILD/compile-netware-standard:
Auto merged
mysql-test/t/rpl_empty_master_crash.test:
Auto merged
mysql-test/t/rpl_error_ignored_table.test:
Auto merged
mysql-test/t/rpl_flush_log_loop.test:
Auto merged
mysql-test/t/rpl_loaddata.test:
Auto merged
mysql-test/t/rpl_loaddata_rule_m.test:
Auto merged
mysql-test/t/rpl_loaddata_rule_s.test:
Auto merged
mysql-test/t/rpl_max_relay_size.test:
Auto merged
mysql-test/t/rpl_openssl.test:
Auto merged
mysql-test/t/rpl_relayrotate-slave.opt:
Auto merged
mysql-test/t/rpl_reset_slave.test:
Auto merged
mysql-test/t/rpl_trunc_binlog.test:
Auto merged
mysql-test/t/rpl_until.test:
Auto merged
mysql-test/t/rpl_user_variables.test:
Auto merged
mysql-test/t/subselect.test:
Auto merged
scripts/make_binary_distribution.sh:
Auto merged
scripts/mysql_create_system_tables.sh:
Auto merged
scripts/mysql_fix_privilege_tables.sql:
Auto merged
scripts/mysql_install_db.sh:
Auto merged
sql/filesort.cc:
Auto merged
sql/ha_berkeley.cc:
Auto merged
sql/ha_berkeley.h:
Auto merged
sql/ha_innodb.h:
Auto merged
sql/ha_myisam.cc:
Auto merged
sql/handler.cc:
Auto merged
sql/handler.h:
Auto merged
sql/item.cc:
Auto merged
sql/item.h:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_cmpfunc.h:
Auto merged
sql/item_create.cc:
Auto merged
sql/item_create.h:
Auto merged
sql/item_subselect.cc:
Auto merged
sql/item_sum.cc:
Auto merged
sql/item_sum.h:
Auto merged
sql/item_timefunc.h:
Auto merged
sql/lock.cc:
Auto merged
sql/log_event.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/net_serv.cc:
Auto merged
sql/protocol.cc:
Auto merged
sql/protocol.h:
Auto merged
sql/repl_failsafe.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_acl.h:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_cache.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_db.cc:
Auto merged
sql/sql_delete.cc:
Auto merged
sql/sql_derived.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_list.h:
Auto merged
sql/sql_load.cc:
Auto merged
sql/sql_rename.cc:
Auto merged
sql/sql_repl.cc:
Auto merged
sql/sql_repl.h:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_select.h:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_test.cc:
Auto merged
sql/sql_update.cc:
Auto merged
sql-common/client.c:
Auto merged
tests/client_test.c:
Auto merged
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 389 |
1 files changed, 262 insertions, 127 deletions
diff --git a/sql/field.cc b/sql/field.cc index d26534b5ac7..d099da2d959 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -107,7 +107,7 @@ bool test_if_int(const char *str, int length, const char *int_end, return 1; } - +#ifdef NOT_USED static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) { cs= system_charset_info; // QQ move test_if_real into CHARSET_INFO struct @@ -159,16 +159,9 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) } return 1; } +#endif -static inline uint field_length_without_space(const char *ptr, uint length) -{ - const char *end= ptr+length; - while (end > ptr && end[-1] == ' ') - end--; - return (uint) (end-ptr); -} - /* Tables of filed type compatibility. @@ -301,11 +294,12 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg) :ptr(ptr_arg),null_ptr(null_ptr_arg), - table(table_arg),table_name(table_arg ? table_arg->table_name : 0), + table(table_arg),orig_table(table_arg), + table_name(table_arg ? table_arg->table_name : 0), field_name(field_name_arg), query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0), unireg_check(unireg_check_arg), - field_length(length_arg),null_bit(null_bit_arg),abs_offset(0) + field_length(length_arg),null_bit(null_bit_arg) { flags=null_ptr ? 0: NOT_NULL_FLAG; comment.str= (char*) ""; @@ -349,9 +343,10 @@ void Field_num::add_zerofill_and_unsigned(String &res) const void Field_num::make_field(Send_field *field) { /* table_cache_key is not set for temp tables */ - field->db_name=table->table_cache_key ? table->table_cache_key : ""; - field->org_table_name=table->real_name; - field->table_name=table_name; + field->db_name= (orig_table->table_cache_key ? orig_table->table_cache_key : + ""); + field->org_table_name= orig_table->real_name; + field->table_name= orig_table->table_name; field->col_name=field->org_col_name=field_name; field->charsetnr= charset()->number; field->length=field_length; @@ -364,9 +359,10 @@ void Field_num::make_field(Send_field *field) void Field_str::make_field(Send_field *field) { /* table_cache_key is not set for temp tables */ - field->db_name=table->table_cache_key ? table->table_cache_key : ""; - field->org_table_name=table->real_name; - field->table_name=table_name; + field->db_name= (orig_table->table_cache_key ? orig_table->table_cache_key : + ""); + field->org_table_name= orig_table->real_name; + field->table_name= orig_table->table_name; field->col_name=field->org_col_name=field_name; field->charsetnr= charset()->number; field->length=field_length; @@ -2264,20 +2260,23 @@ void Field_longlong::sql_type(String &res) const add_zerofill_and_unsigned(res); } + /**************************************************************************** -** single precision float + single precision float ****************************************************************************/ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) { - int err; - Field_float::store(my_strntod(cs,(char*) from,len,(char**)NULL,&err)); - if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) + int error; + char *end; + double nr= my_strntod(cs,(char*) from,len,&end,&error); + if (error || ((uint) (end-from) != len && current_thd->count_cuted_fields)) { + error= 1; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); - return 1; } - return (err) ? 1 : 0; + Field_float::store(nr); + return error; } @@ -2285,28 +2284,48 @@ int Field_float::store(double nr) { float j; int error= 0; - if (dec < NOT_FIXED_DEC) - nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point - if (unsigned_flag && nr < 0) + + if (isnan(nr)) { + j= 0; + set_null(); set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); - nr=0; error= 1; } - if (nr < -FLT_MAX) + else if (unsigned_flag && nr < 0) { - j= -FLT_MAX; + j= 0; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } - else if (nr > FLT_MAX) + else { - j=FLT_MAX; - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); - error= 1; + double max_value; + if (dec >= NOT_FIXED_DEC) + { + max_value= FLT_MAX; + } + else + { + max_value= (log_10[field_length]-1)/log_10[dec]; + nr= floor(nr*log_10[dec]+0.5)/log_10[dec]; + } + if (nr < -max_value) + { + j= (float)-max_value; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); + error= 1; + } + else if (nr > max_value) + { + j= (float)max_value; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); + error= 1; + } + else + j= (float) nr; } - else - j= (float) nr; + #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -2537,48 +2556,69 @@ void Field_float::sql_type(String &res) const add_zerofill_and_unsigned(res); } + /**************************************************************************** -** double precision floating point numbers + double precision floating point numbers ****************************************************************************/ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) { - int err; - double j= my_strntod(cs,(char*) from,len,(char**)0,&err); - if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs)) + int error; + char *end; + double nr= my_strntod(cs,(char*) from, len, &end, &error); + if (error || ((uint) (end-from) != len && current_thd->count_cuted_fields)) { + error= 1; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); - err= 1; } - if (unsigned_flag && j < 0) - { - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); - j=0; - err= 1; - } -#ifdef WORDS_BIGENDIAN - if (table->db_low_byte_first) - { - float8store(ptr,j); - } - else -#endif - doublestore(ptr,j); - return err; + Field_double::store(nr); + return error; } int Field_double::store(double nr) { int error= 0; - if (dec < NOT_FIXED_DEC) - nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point - if (unsigned_flag && nr < 0) + + if (isnan(nr)) { + nr= 0; + set_null(); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); + error= 1; + } + else if (unsigned_flag && nr < 0) + { + nr= 0; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); - nr=0; error= 1; } + else + { + double max_value; + if (dec >= NOT_FIXED_DEC) + { + max_value= DBL_MAX; + } + else + { + max_value= (log_10[field_length]-1)/log_10[dec]; + nr= floor(nr*log_10[dec]+0.5)/log_10[dec]; + } + if (nr < -max_value) + { + nr= -max_value; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); + error= 1; + } + else if (nr > max_value) + { + nr= max_value; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); + error= 1; + } + } + #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -2742,14 +2782,8 @@ int Field_double::cmp(const char *a_ptr, const char *b_ptr) else #endif { -/* could this ALWAYS be 2 calls to doubleget() ?? */ -#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) doubleget(a, a_ptr); doubleget(b, b_ptr); -#else - memcpy_fixed(&a,a_ptr,sizeof(double)); - memcpy_fixed(&b,b_ptr,sizeof(double)); -#endif } return (a < b) ? -1 : (a > b) ? 1 : 0; } @@ -2769,12 +2803,7 @@ void Field_double::sort_string(char *to,uint length __attribute__((unused))) } else #endif -/* could this ALWAYS be 2 calls to doubleget() ?? */ -#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) doubleget(nr,ptr); -#else - memcpy_fixed(&nr,ptr,sizeof(nr)); -#endif change_double_for_sort(nr, (byte*) to); } @@ -2795,11 +2824,50 @@ void Field_double::sql_type(String &res) const } -/**************************************************************************** -** timestamp -** The first timestamp in the table is automaticly updated -** by handler.cc. The form->timestamp points at the automatic timestamp. -****************************************************************************/ +/* + TIMESTAMP type. + Holds datetime values in range from 1970-01-01 00:00:01 UTC to + 2038-01-01 00:00:00 UTC stored as number of seconds since Unix + Epoch in UTC. + + Up to one of timestamps columns in the table can be automatically + set on row update and/or have NOW() as default value. + TABLE::timestamp_field points to Field object for such timestamp with + auto-set-on-update. TABLE::time_stamp holds offset in record + 1 for this + field, and is used by handler code which performs updates required. + + Actually SQL-99 says that we should allow niladic functions (like NOW()) + as defaults for any field. Current limitations (only NOW() and only + for one TIMESTAMP field) are because of restricted binary .frm format + and should go away in the future. + + Also because of this limitation of binary .frm format we use 5 different + unireg_check values with TIMESTAMP field to distinguish various cases of + DEFAULT or ON UPDATE values. These values are: + + TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with + auto-set-on-update (or now() as default) in this table before, then this + field has NOW() as default and is updated when row changes, else it is + field which has 0 as default value and is not automaitcally updated. + TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update + automatically (TIMESTAMP DEFAULT NOW()) + TIMESTAMP_UN_FIELD - field which is set on update automatically but has not + NOW() as default (but it may has 0 or some other const timestamp as + default) (TIMESTAMP ON UPDATE NOW()). + TIMESTAMP_DNUN_FIELD - field which has now() as default and is auto-set on + update. (TIMESTAMP DEFAULT NOW() ON UPDATE NOW()) + NONE - field which is not auto-set on update with some other than NOW() + default value (TIMESTAMP DEFAULT 0). + + Note that TIMESTAMP_OLD_FIELD's are never created explicitly now, they are + left only for preserving ability to read old tables. Such fields replaced + with their newer analogs in CREATE TABLE and in SHOW CREATE TABLE. This is + because we want to prefer NONE unireg_check before TIMESTAMP_OLD_FIELD for + "TIMESTAMP DEFAULT 'Const'" field. (Old timestamps allowed such + specification too but ignored default value for first timestamp, which of + course is non-standard.) In most cases user won't notice any change, only + exception is different behavior of old/new timestamps during ALTER TABLE. + */ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, @@ -2810,15 +2878,37 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, unireg_check_arg, field_name_arg, table_arg, cs) { flags|=ZEROFILL_FLAG; /* 4.0 MYD compatibility */ - if (table && !table->timestamp_field) + if (table && !table->timestamp_field && + unireg_check != NONE) { - table->timestamp_field= this; // Automatic timestamp - table->time_stamp=(ulong) (ptr_arg - (char*) table->record[0])+1; + /* This timestamp has auto-update */ + table->timestamp_field= this; flags|=TIMESTAMP_FLAG; } } +/* + Sets TABLE::timestamp_default_now and TABLE::timestamp_on_update_now + members according to unireg type of this TIMESTAMP field. + + SYNOPSIS + Field_timestamp::set_timestamp_offsets() + +*/ +void Field_timestamp::set_timestamp_offsets() +{ + ulong timestamp= (ulong) (ptr - (char*) table->record[0]) + 1; + + DBUG_ASSERT(table->timestamp_field == this && unireg_check != NONE); + + table->timestamp_default_now= + (unireg_check == TIMESTAMP_UN_FIELD)? 0 : timestamp; + table->timestamp_on_update_now= + (unireg_check == TIMESTAMP_DN_FIELD)? 0 : timestamp; +} + + int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) { long tmp=(long) str_to_timestamp(from,len); @@ -2933,10 +3023,10 @@ int Field_timestamp::store(longlong nr) { long not_used; - if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1) + if (!(timestamp= my_gmt_sec(&l_time, ¬_used))) goto err; - timestamp= my_gmt_sec(&l_time, ¬_used); } + #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -4075,10 +4165,10 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) Make sure we don't break a multibyte sequence as well as don't copy a malformed data. */ - copy_length= field_charset->cset->wellformedlen(field_charset, - from,from+length, - field_length/ - field_charset->mbmaxlen); + copy_length= field_charset->cset->well_formed_len(field_charset, + from,from+length, + field_length/ + field_charset->mbmaxlen); memcpy(ptr,from,copy_length); if (copy_length < field_length) // Append spaces if shorter field_charset->cset->fill(field_charset,ptr+copy_length, @@ -4165,10 +4255,10 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr) void Field_string::sort_string(char *to,uint length) { uint tmp=my_strnxfrm(field_charset, - (unsigned char *)to, length, - (unsigned char *) ptr, field_length); + (unsigned char *) to, length, + (unsigned char *) ptr, field_length); if (tmp < length) - bzero(to + tmp, length - tmp); + field_charset->cset->fill(field_charset, to + tmp, length - tmp, ' '); } @@ -4180,7 +4270,8 @@ void Field_string::sql_type(String &res) const (field_length > 3 && (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? - "varchar" : "char"), + (has_charset() ? "varchar" : "varbinary") : + (has_charset() ? "char" : "binary")), (int) field_length / charset()->mbmaxlen); res.length(length); } @@ -4340,7 +4431,8 @@ void Field_varstring::sort_string(char *to,uint length) (unsigned char *) to, length, (unsigned char *)ptr+2, tot_length); if (tot_length < length) - bzero(to+tot_length,length-tot_length); + field_charset->cset->fill(field_charset, to+tot_length,length-tot_length, + binary() ? (char) 0 : ' '); } @@ -4571,11 +4663,15 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) } copy_length= max_data_length(); - if (copy_length > length) - copy_length= length; - copy_length= field_charset->cset->wellformedlen(field_charset, - from,from+copy_length, - field_length); + /* + copy_length is ok as last argument to well_formed_len as this is never + used to limit the length of the data. The cut of long data is done with + the 'min()' call below. + */ + copy_length= field_charset->cset->well_formed_len(field_charset, + from,from + + min(length, copy_length), + copy_length); if (copy_length < length) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); @@ -4711,18 +4807,28 @@ void Field_blob::get_key_image(char *buff,uint length, #ifdef HAVE_SPATIAL if (type == itMBR) { - if (!blob_length) + const char *dummy; + MBR mbr; + Geometry_buffer buffer; + Geometry *gobj; + + if (blob_length < SRID_SIZE) + { + bzero(buff, SIZEOF_STORED_DOUBLE*4); return; + } get_ptr(&blob); - - MBR mbr; - Geometry gobj; - gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE); - gobj.get_mbr(&mbr); - float8store(buff, mbr.xmin); - float8store(buff+8, mbr.xmax); - float8store(buff+16, mbr.ymin); - float8store(buff+24, mbr.ymax); + gobj= Geometry::create_from_wkb(&buffer, + blob + SRID_SIZE, blob_length - SRID_SIZE); + if (gobj->get_mbr(&mbr, &dummy)) + bzero(buff, SIZEOF_STORED_DOUBLE*4); + else + { + float8store(buff, mbr.xmin); + float8store(buff+8, mbr.xmax); + float8store(buff+16, mbr.ymin); + float8store(buff+24, mbr.ymax); + } return; } #endif /*HAVE_SPATIAL*/ @@ -4780,7 +4886,9 @@ void Field_blob::sort_string(char *to,uint length) (unsigned char *)to, length, (unsigned char *)blob, blob_length); if (blob_length < length) - bzero(to+blob_length, length-blob_length); + field_charset->cset->fill(field_charset, to+blob_length, + length-blob_length, + binary() ? (char) 0 : ' '); } } @@ -4935,6 +5043,7 @@ uint Field_blob::max_packed_col_length(uint max_length) return (max_length > 255 ? 2 : 1)+max_length; } + #ifdef HAVE_SPATIAL void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs, @@ -4943,17 +5052,28 @@ void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs, length-= HA_KEY_BLOB_LENGTH; ulong blob_length= get_length(ptr); char *blob; - get_ptr(&blob); - + const char *dummy; MBR mbr; - Geometry gobj; - gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE); - gobj.get_mbr(&mbr); - float8store(buff, mbr.xmin); - float8store(buff + 8, mbr.xmax); - float8store(buff + 16, mbr.ymin); - float8store(buff + 24, mbr.ymax); - return; + + if (blob_length < SRID_SIZE) + { + bzero(buff, SIZEOF_STORED_DOUBLE*4); + return; + } + get_ptr(&blob); + Geometry_buffer buffer; + Geometry *gobj; + gobj= Geometry::create_from_wkb(&buffer, + blob + SRID_SIZE, blob_length - SRID_SIZE); + if (gobj->get_mbr(&mbr, &dummy)) + bzero(buff, SIZEOF_STORED_DOUBLE*4); + else + { + float8store(buff, mbr.xmin); + float8store(buff + 8, mbr.xmax); + float8store(buff + 16, mbr.ymin); + float8store(buff + 24, mbr.ymax); + } } @@ -4997,17 +5117,17 @@ void Field_geom::sql_type(String &res) const int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) { if (!length) - { bzero(ptr, Field_blob::pack_length()); - } else { - // Should check given WKB - if (length < 4 + 1 + 4 + 8 + 8) // SRID + WKB_HEADER + X + Y - return 1; - uint32 wkb_type= uint4korr(from + 5); - if (wkb_type < 1 || wkb_type > 7) - return 1; + // Check given WKB + uint32 wkb_type; + if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2) + goto err; + wkb_type= uint4korr(from + WKB_HEADER_SIZE); + if (wkb_type < (uint32) Geometry::wkb_point || + wkb_type > (uint32) Geometry::wkb_end) + return -1; Field_blob::store_length(length); if (table->copy_blobs || length <= MAX_FIELD_WIDTH) { // Must make a copy @@ -5017,6 +5137,10 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) bmove(ptr + packlength, (char*) &from, sizeof(char*)); } return 0; + +err: + bzero(ptr, Field_blob::pack_length()); + return -1; } #endif /*HAVE_SPATIAL*/ @@ -5455,7 +5579,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length) case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen default: return 0; } - return 0; // This shouldn't happen + return 0; // Keep compiler happy } @@ -5488,6 +5612,18 @@ Field *make_field(char *ptr, uint32 field_length, null_pos=0; null_bit=0; } + + switch (field_type) + { + case FIELD_TYPE_DATE: + case FIELD_TYPE_NEWDATE: + case FIELD_TYPE_TIME: + case FIELD_TYPE_DATETIME: + case FIELD_TYPE_TIMESTAMP: + field_charset= &my_charset_bin; + default: break; + } + if (f_is_alpha(pack_flag)) { if (!f_is_packed(pack_flag)) @@ -5644,8 +5780,7 @@ create_field::create_field(Field *old_field,Field *orig_field) interval=0; def=0; if (!old_field->is_real_null() && ! (flags & BLOB_FLAG) && - old_field->type() != FIELD_TYPE_TIMESTAMP && old_field->ptr && - orig_field) + old_field->ptr && orig_field) { char buff[MAX_FIELD_WIDTH],*pos; String tmp(buff,sizeof(buff), charset); @@ -5660,7 +5795,7 @@ create_field::create_field(Field *old_field,Field *orig_field) { pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1); pos[tmp.length()]=0; - def=new Item_string(pos,tmp.length(), charset); + def= new Item_string(pos, tmp.length(), charset); } } #ifdef HAVE_SPATIAL |