diff --git a/include/typelib.h b/include/typelib.h index 4d6a90ad51e..fe19f1001d4 100644 --- a/include/typelib.h +++ b/include/typelib.h @@ -18,6 +18,8 @@ #ifndef _typelib_h #define _typelib_h +#include "my_alloc.h" + typedef struct st_typelib { /* Different types saved here */ unsigned int count; /* How many types */ const char *name; /* Name of typelib */ @@ -28,6 +30,7 @@ typedef struct st_typelib { /* Different types saved here */ extern int find_type(char *x,TYPELIB *typelib,unsigned int full_name); extern void make_type(char *to,unsigned int nr,TYPELIB *typelib); extern const char *get_type(TYPELIB *typelib,unsigned int nr); +extern TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from); extern TYPELIB sql_protocol_typelib; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 6859de2ed63..fb2e456833c 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -5816,4 +5816,20 @@ DROP TABLE bug23760, bug23760_log| DROP PROCEDURE bug23760_update_log| DROP PROCEDURE bug23760_test_row_count| DROP FUNCTION bug23760_rc_test| +DROP PROCEDURE IF EXISTS bug24117| +DROP TABLE IF EXISTS t3| +CREATE TABLE t3(c1 ENUM('abc'))| +INSERT INTO t3 VALUES('abc')| +CREATE PROCEDURE bug24117() +BEGIN +DECLARE t3c1 ENUM('abc'); +DECLARE mycursor CURSOR FOR SELECT c1 FROM t3; +OPEN mycursor; +FLUSH TABLES; +FETCH mycursor INTO t3c1; +CLOSE mycursor; +END| +CALL bug24117()| +DROP PROCEDURE bug24117| +DROP TABLE t3| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index ba1180ffaff..19c70b1bd1e 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -6778,6 +6778,30 @@ DROP PROCEDURE bug23760_update_log| DROP PROCEDURE bug23760_test_row_count| DROP FUNCTION bug23760_rc_test| +# +# BUG#24117: server crash on a FETCH with a cursor on a table which is not in +# the table cache +# + +--disable_warnings +DROP PROCEDURE IF EXISTS bug24117| +DROP TABLE IF EXISTS t3| +--enable_warnings +CREATE TABLE t3(c1 ENUM('abc'))| +INSERT INTO t3 VALUES('abc')| +CREATE PROCEDURE bug24117() +BEGIN + DECLARE t3c1 ENUM('abc'); + DECLARE mycursor CURSOR FOR SELECT c1 FROM t3; + OPEN mycursor; + FLUSH TABLES; + FETCH mycursor INTO t3c1; + CLOSE mycursor; +END| +CALL bug24117()| +DROP PROCEDURE bug24117| +DROP TABLE t3| + # # NOTE: The delimiter is `|`, and not `;`. It is changed to `;` # at the end of the file! diff --git a/mysys/typelib.c b/mysys/typelib.c index d329b687668..8906b702aa8 100644 --- a/mysys/typelib.c +++ b/mysys/typelib.c @@ -119,3 +119,54 @@ const char *get_type(TYPELIB *typelib, uint nr) return(typelib->type_names[nr]); return "?"; } + + +/* + Create a copy of a specified TYPELIB structure. + + SYNOPSIS + copy_typelib() + root pointer to a MEM_ROOT object for allocations + from pointer to a source TYPELIB structure + + RETURN + pointer to the new TYPELIB structure on successful copy, or + NULL otherwise +*/ + +TYPELIB *copy_typelib(MEM_ROOT *root, TYPELIB *from) +{ + TYPELIB *to; + uint i; + + if (!from) + return NULL; + + if (!(to= (TYPELIB*) alloc_root(root, sizeof(TYPELIB)))) + return NULL; + + if (!(to->type_names= (const char **) + alloc_root(root, (sizeof(char *) + sizeof(int)) * (from->count + 1)))) + return NULL; + to->type_lengths= (unsigned int *)(to->type_names + from->count + 1); + to->count= from->count; + if (from->name) + { + if (!(to->name= strdup_root(root, from->name))) + return NULL; + } + else + to->name= NULL; + + for (i= 0; i < from->count; i++) + { + if (!(to->type_names[i]= strmake_root(root, from->type_names[i], + from->type_lengths[i]))) + return NULL; + to->type_lengths[i]= from->type_lengths[i]; + } + to->type_names[to->count]= NULL; + to->type_lengths[to->count]= 0; + + return to; +} diff --git a/sql/field.cc b/sql/field.cc index 4245d401f53..0dd3dd6b417 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8029,6 +8029,16 @@ void Field_enum::sql_type(String &res) const } +Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table, + bool keep_type) +{ + Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type); + if (res) + res->typelib= copy_typelib(root, typelib); + return res; +} + + /* set type. This is a string which can have a collection of different values. diff --git a/sql/field.h b/sql/field.h index 3e2be248627..9d979e81c9c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1354,6 +1354,7 @@ public: { flags|=ENUM_FLAG; } + Field *new_field(MEM_ROOT *root, struct st_table *new_table, bool keep_type); enum_field_types type() const { return FIELD_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } enum Item_result cast_to_int_type () const { return INT_RESULT; }