Bug#3788

  Crashes with stored procedure return non-string values
  Also fixes Bug#2773
parent 05eb8af4
...@@ -202,7 +202,7 @@ select parameter_style, sql_data_access, dtd_identifier ...@@ -202,7 +202,7 @@ select parameter_style, sql_data_access, dtd_identifier
from information_schema.routines; from information_schema.routines;
parameter_style sql_data_access dtd_identifier parameter_style sql_data_access dtd_identifier
SQL CONTAINS SQL NULL SQL CONTAINS SQL NULL
SQL CONTAINS SQL int SQL CONTAINS SQL int(11)
show procedure status; show procedure status;
Db Name Type Definer Modified Created Security_type Comment Db Name Type Definer Modified Created Security_type Comment
test sel2 PROCEDURE root@localhost # # DEFINER test sel2 PROCEDURE root@localhost # # DEFINER
......
...@@ -951,7 +951,7 @@ comment 'Characteristics procedure test' ...@@ -951,7 +951,7 @@ comment 'Characteristics procedure test'
return 42| return 42|
show create function chistics| show create function chistics|
Function sql_mode Create Function Function sql_mode Create Function
chistics CREATE FUNCTION `test`.`chistics`() RETURNS int chistics CREATE FUNCTION `test`.`chistics`() RETURNS int(11)
DETERMINISTIC DETERMINISTIC
SQL SECURITY INVOKER SQL SECURITY INVOKER
COMMENT 'Characteristics procedure test' COMMENT 'Characteristics procedure test'
...@@ -964,7 +964,7 @@ no sql ...@@ -964,7 +964,7 @@ no sql
comment 'Characteristics function test'| comment 'Characteristics function test'|
show create function chistics| show create function chistics|
Function sql_mode Create Function Function sql_mode Create Function
chistics CREATE FUNCTION `test`.`chistics`() RETURNS int chistics CREATE FUNCTION `test`.`chistics`() RETURNS int(11)
NO SQL NO SQL
DETERMINISTIC DETERMINISTIC
SQL SECURITY INVOKER SQL SECURITY INVOKER
...@@ -1214,7 +1214,7 @@ show procedure status; ...@@ -1214,7 +1214,7 @@ show procedure status;
end end
call bug2267_4()| call bug2267_4()|
Function sql_mode Create Function Function sql_mode Create Function
fac CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint unsigned fac CREATE FUNCTION `test`.`fac`(n int unsigned) RETURNS bigint(20) unsigned
begin begin
declare f bigint unsigned default 1; declare f bigint unsigned default 1;
while n > 1 do while n > 1 do
...@@ -1576,11 +1576,11 @@ bug2564_2 ANSI_QUOTES CREATE PROCEDURE "test"."bug2564_2"() ...@@ -1576,11 +1576,11 @@ bug2564_2 ANSI_QUOTES CREATE PROCEDURE "test"."bug2564_2"()
insert into "t1" values ('foo', 1) insert into "t1" values ('foo', 1)
show create function bug2564_3| show create function bug2564_3|
Function sql_mode Create Function Function sql_mode Create Function
bug2564_3 CREATE FUNCTION `test`.`bug2564_3`(x int, y int) RETURNS int bug2564_3 CREATE FUNCTION `test`.`bug2564_3`(x int, y int) RETURNS int(11)
return x || y return x || y
show create function bug2564_4| show create function bug2564_4|
Function sql_mode Create Function Function sql_mode Create Function
bug2564_4 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI CREATE FUNCTION "test"."bug2564_4"(x int, y int) RETURNS int bug2564_4 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI CREATE FUNCTION "test"."bug2564_4"(x int, y int) RETURNS int(11)
return x || y return x || y
drop procedure bug2564_1| drop procedure bug2564_1|
drop procedure bug2564_2| drop procedure bug2564_2|
...@@ -1645,6 +1645,28 @@ drop procedure bug4579_1| ...@@ -1645,6 +1645,28 @@ drop procedure bug4579_1|
drop procedure bug4579_2| drop procedure bug4579_2|
drop table t3| drop table t3|
drop table if exists t3| drop table if exists t3|
drop procedure if exists bug2773|
create function bug2773() returns int return null|
create table t3 as select bug2773()|
show create table t3|
Table Create Table
t3 CREATE TABLE `t3` (
`bug2773()` int(11) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t3|
drop function bug2773|
drop procedure if exists bug3788|
create function bug3788() returns date return cast("2005-03-04" as date)|
select bug3788()|
bug3788()
2005-03-04
drop function bug3788|
create function bug3788() returns binary(5) return 5|
select bug3788()|
bug3788()
5
drop function bug3788|
drop table if exists t3|
create table t3 (f1 int, f2 int, f3 int)| create table t3 (f1 int, f2 int, f3 int)|
insert into t3 values (1,1,1)| insert into t3 values (1,1,1)|
drop procedure if exists bug4726| drop procedure if exists bug4726|
......
...@@ -2063,6 +2063,35 @@ drop procedure bug4579_1| ...@@ -2063,6 +2063,35 @@ drop procedure bug4579_1|
drop procedure bug4579_2| drop procedure bug4579_2|
drop table t3| drop table t3|
#
# BUG#2773: Function's data type ignored in stored procedures
#
--disable_warnings
drop table if exists t3|
drop procedure if exists bug2773|
--enable_warnings
create function bug2773() returns int return null|
create table t3 as select bug2773()|
show create table t3|
drop table t3|
drop function bug2773|
#
# BUG#3788: Stored procedure packet error
#
--disable_warnings
drop procedure if exists bug3788|
--enable_warnings
create function bug3788() returns date return cast("2005-03-04" as date)|
select bug3788()|
drop function bug3788|
create function bug3788() returns binary(5) return 5|
select bug3788()|
drop function bug3788|
# #
# BUG#4726 # BUG#4726
......
...@@ -3524,7 +3524,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ...@@ -3524,7 +3524,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
enum_parsing_place place= NO_MATTER; enum_parsing_place place= NO_MATTER;
SELECT_LEX *current_sel= thd->lex->current_select; SELECT_LEX *current_sel= thd->lex->current_select;
if (!ref) if (!ref || ref == not_found_item)
{ {
SELECT_LEX_UNIT *prev_unit= current_sel->master_unit(); SELECT_LEX_UNIT *prev_unit= current_sel->master_unit();
SELECT_LEX *outer_sel= prev_unit->outer_select(); SELECT_LEX *outer_sel= prev_unit->outer_select();
......
...@@ -4318,13 +4318,33 @@ longlong Item_func_row_count::val_int() ...@@ -4318,13 +4318,33 @@ longlong Item_func_row_count::val_int()
Item_func_sp::Item_func_sp(sp_name *name) Item_func_sp::Item_func_sp(sp_name *name)
:Item_func(), m_name(name), m_sp(NULL) :Item_func(), m_name(name), m_sp(NULL)
{ {
char *empty_name= (char *) "";
maybe_null= 1;
m_name->init_qname(current_thd); m_name->init_qname(current_thd);
bzero(&dummy_table, sizeof(dummy_table));
dummy_table.share.table_cache_key = empty_name;
dummy_table.share.table_name = empty_name;
dummy_table.table.alias = empty_name;
dummy_table.share.table_name = empty_name;
dummy_table.table.maybe_null = maybe_null;
dummy_table.table.in_use= current_thd;
dummy_table.table.s = &dummy_table.share;
} }
Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list) Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list)
:Item_func(list), m_name(name), m_sp(NULL) :Item_func(list), m_name(name), m_sp(NULL)
{ {
char *empty_name= (char *) "";
maybe_null= 1;
m_name->init_qname(current_thd); m_name->init_qname(current_thd);
bzero(&dummy_table, sizeof(dummy_table));
dummy_table.share.table_cache_key = empty_name;
dummy_table.share.table_name = empty_name;
dummy_table.table.alias = empty_name;
dummy_table.share.table_name = empty_name;
dummy_table.table.maybe_null = maybe_null;
dummy_table.table.in_use= current_thd;
dummy_table.table.s = &dummy_table.share;
} }
const char * const char *
...@@ -4349,6 +4369,18 @@ Item_func_sp::func_name() const ...@@ -4349,6 +4369,18 @@ Item_func_sp::func_name() const
} }
Field *
Item_func_sp::sp_result_field(void) const
{
Field *field= 0;
THD *thd= current_thd;
DBUG_ENTER("Item_func_sp::sp_result_field");
if (m_sp)
field= m_sp->make_field(max_length, name, &dummy_table.table);
DBUG_RETURN(field);
}
int int
Item_func_sp::execute(Item **itp) Item_func_sp::execute(Item **itp)
{ {
...@@ -4404,17 +4436,38 @@ Item_func_sp::execute(Item **itp) ...@@ -4404,17 +4436,38 @@ Item_func_sp::execute(Item **itp)
} }
void
Item_func_sp::make_field(Send_field *tmp_field)
{
Field *field;
DBUG_ENTER("Item_func_sp::make_field");
if (! m_sp)
m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
if ((field= sp_result_field()))
{
field->make_field(tmp_field);
delete field;
DBUG_VOID_RETURN;
}
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
init_make_field(tmp_field, MYSQL_TYPE_VARCHAR);
DBUG_VOID_RETURN;
}
enum enum_field_types enum enum_field_types
Item_func_sp::field_type() const Item_func_sp::field_type() const
{ {
Field *field= 0;
DBUG_ENTER("Item_func_sp::field_type"); DBUG_ENTER("Item_func_sp::field_type");
if (! m_sp) if (! m_sp)
m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
if (m_sp) if ((field= sp_result_field()))
{ {
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns)); enum_field_types result= field->type();
DBUG_RETURN(m_sp->m_returns); delete field;
DBUG_RETURN(result);
} }
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
DBUG_RETURN(MYSQL_TYPE_VARCHAR); DBUG_RETURN(MYSQL_TYPE_VARCHAR);
...@@ -4424,14 +4477,17 @@ Item_func_sp::field_type() const ...@@ -4424,14 +4477,17 @@ Item_func_sp::field_type() const
Item_result Item_result
Item_func_sp::result_type() const Item_func_sp::result_type() const
{ {
Field *field= 0;
DBUG_ENTER("Item_func_sp::result_type"); DBUG_ENTER("Item_func_sp::result_type");
DBUG_PRINT("info", ("m_sp = %p", m_sp)); DBUG_PRINT("info", ("m_sp = %p", m_sp));
if (! m_sp) if (! m_sp)
m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
if (m_sp) if ((field= sp_result_field()))
{ {
DBUG_RETURN(m_sp->result()); Item_result result= field->result_type();
delete field;
DBUG_RETURN(result);
} }
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
DBUG_RETURN(STRING_RESULT); DBUG_RETURN(STRING_RESULT);
...@@ -4450,7 +4506,7 @@ Item_func_sp::fix_length_and_dec() ...@@ -4450,7 +4506,7 @@ Item_func_sp::fix_length_and_dec()
} }
else else
{ {
switch (m_sp->result()) { switch (result_type()) {
case STRING_RESULT: case STRING_RESULT:
maybe_null= 1; maybe_null= 1;
max_length= MAX_BLOB_WIDTH; max_length= MAX_BLOB_WIDTH;
...@@ -4485,3 +4541,19 @@ longlong Item_func_found_rows::val_int() ...@@ -4485,3 +4541,19 @@ longlong Item_func_found_rows::val_int()
return thd->found_rows(); return thd->found_rows();
} }
Field *
Item_func_sp::tmp_table_field(TABLE *t_arg)
{
Field *res= 0;
enum_field_types ftype;
DBUG_ENTER("Item_func_sp::tmp_table_field");
if (m_sp)
res= m_sp->make_field(max_length, (const char *)name, t_arg);
if (!res)
res= Item_func::tmp_table_field(t_arg);
DBUG_RETURN(res);
}
...@@ -1250,8 +1250,13 @@ class Item_func_sp :public Item_func ...@@ -1250,8 +1250,13 @@ class Item_func_sp :public Item_func
private: private:
sp_name *m_name; sp_name *m_name;
mutable sp_head *m_sp; mutable sp_head *m_sp;
mutable struct {
TABLE table;
TABLE_SHARE share;
} dummy_table;
int execute(Item **itp); int execute(Item **itp);
Field *sp_result_field(void) const;
public: public:
...@@ -1266,6 +1271,10 @@ public: ...@@ -1266,6 +1271,10 @@ public:
enum enum_field_types field_type() const; enum enum_field_types field_type() const;
Field *tmp_table_field(TABLE *t_arg);
void make_field(Send_field *tmp_field);
Item_result result_type() const; Item_result result_type() const;
longlong val_int() longlong val_int()
......
...@@ -629,6 +629,10 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t); ...@@ -629,6 +629,10 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field, Item ***copy_func, Field **from_field,
bool group, bool modify_item, uint convert_blob_length); bool group, bool modify_item, uint convert_blob_length);
int prepare_create_field(create_field *sql_field,
uint &blob_columns,
int &timestamps, int &timestamps_with_niladic,
uint table_flags);
int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
List<create_field> &fields, List<create_field> &fields,
List<Key> &keys, uint &db_options, List<Key> &keys, uint &db_options,
...@@ -837,6 +841,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type, ...@@ -837,6 +841,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
char *change, List<String> *interval_list, char *change, List<String> *interval_list,
CHARSET_INFO *cs, CHARSET_INFO *cs,
uint uint_geom_type); uint uint_geom_type);
create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
char *length, char *decimals,
uint type_modifier,
Item *default_value, Item *on_update_value,
LEX_STRING *comment, char *change,
List<String> *interval_list, CHARSET_INFO *cs,
uint uint_geom_type);
void store_position_for_column(const char *name); void store_position_for_column(const char *name);
bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0); bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0);
void add_join_on(TABLE_LIST *b,Item *expr); void add_join_on(TABLE_LIST *b,Item *expr);
......
...@@ -334,6 +334,22 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) ...@@ -334,6 +334,22 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
} }
static void
sp_returns_type(THD *thd, String &result, sp_head *sp)
{
struct {
TABLE table;
TABLE_SHARE share;
} dummy;
Field *field;
bzero(&dummy, sizeof(dummy));
dummy.table.in_use= thd;
dummy.table.s = &dummy.share;
field= sp->make_field(0, 0, &dummy.table);
field->sql_type(result);
delete field;
}
static int static int
db_create_routine(THD *thd, int type, sp_head *sp) db_create_routine(THD *thd, int type, sp_head *sp)
{ {
...@@ -388,9 +404,13 @@ db_create_routine(THD *thd, int type, sp_head *sp) ...@@ -388,9 +404,13 @@ db_create_routine(THD *thd, int type, sp_head *sp)
store((longlong)sp->m_chistics->suid); store((longlong)sp->m_chistics->suid);
table->field[MYSQL_PROC_FIELD_PARAM_LIST]-> table->field[MYSQL_PROC_FIELD_PARAM_LIST]->
store(sp->m_params.str, sp->m_params.length, system_charset_info); store(sp->m_params.str, sp->m_params.length, system_charset_info);
if (sp->m_retstr.str) if (sp->m_type == TYPE_ENUM_FUNCTION)
{
String retstr(64);
sp_returns_type(thd, retstr, sp);
table->field[MYSQL_PROC_FIELD_RETURNS]-> table->field[MYSQL_PROC_FIELD_RETURNS]->
store(sp->m_retstr.str, sp->m_retstr.length, system_charset_info); store(retstr.ptr(), retstr.length(), system_charset_info);
}
table->field[MYSQL_PROC_FIELD_BODY]-> table->field[MYSQL_PROC_FIELD_BODY]->
store(sp->m_body.str, sp->m_body.length, system_charset_info); store(sp->m_body.str, sp->m_body.length, system_charset_info);
table->field[MYSQL_PROC_FIELD_DEFINER]-> table->field[MYSQL_PROC_FIELD_DEFINER]->
......
...@@ -300,11 +300,11 @@ sp_head::init(LEX *lex) ...@@ -300,11 +300,11 @@ sp_head::init(LEX *lex)
*/ */
lex->trg_table_fields.empty(); lex->trg_table_fields.empty();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
m_param_begin= m_param_end= m_returns_begin= m_returns_end= m_body_begin= 0; m_param_begin= m_param_end= m_body_begin= 0;
m_qname.str= m_db.str= m_name.str= m_params.str= m_retstr.str= m_qname.str= m_db.str= m_name.str= m_params.str=
m_body.str= m_defstr.str= 0; m_body.str= m_defstr.str= 0;
m_qname.length= m_db.length= m_name.length= m_params.length= m_qname.length= m_db.length= m_name.length= m_params.length=
m_retstr.length= m_body.length= m_defstr.length= 0; m_body.length= m_defstr.length= 0;
m_returns_cs= NULL; m_returns_cs= NULL;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -346,41 +346,6 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) ...@@ -346,41 +346,6 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
(char *)m_param_begin, m_params.length); (char *)m_param_begin, m_params.length);
} }
if (m_returns_begin && m_returns_end)
{
/* QQ KLUDGE: We can't seem to cut out just the type in the parser
(without the RETURNS), so we'll have to do it here. :-(
Furthermore, if there's a character type as well, it's not include
(beyond the m_returns_end pointer), in which case we need
m_returns_cs. */
char *p= (char *)m_returns_begin+strspn((char *)m_returns_begin,"\t\n\r ");
p+= strcspn(p, "\t\n\r ");
p+= strspn(p, "\t\n\r ");
if (p < (char *)m_returns_end)
m_returns_begin= (uchar *)p;
/* While we're at it, trim the end too. */
p= (char *)m_returns_end-1;
while (p > (char *)m_returns_begin &&
(*p == '\t' || *p == '\n' || *p == '\r' || *p == ' '))
p-= 1;
m_returns_end= (uchar *)p+1;
if (m_returns_cs)
{
String s((char *)m_returns_begin, m_returns_end - m_returns_begin,
system_charset_info);
s.append(' ');
s.append(m_returns_cs->csname);
m_retstr.length= s.length();
m_retstr.str= strmake_root(root, s.ptr(), m_retstr.length);
}
else
{
m_retstr.length= m_returns_end - m_returns_begin;
m_retstr.str= strmake_root(root,
(char *)m_returns_begin, m_retstr.length);
}
}
m_body.length= lex->ptr - m_body_begin; m_body.length= lex->ptr - m_body_begin;
/* Trim nuls at the end */ /* Trim nuls at the end */
n= 0; n= 0;
...@@ -396,6 +361,27 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name) ...@@ -396,6 +361,27 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
TYPELIB *
sp_head::create_typelib(List<String> *src)
{
TYPELIB *result= NULL;
DBUG_ENTER("sp_head::clone_typelib");
if (src->elements)
{
result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB));
result->count= src->elements;
result->name= "";
if (!(result->type_names=(const char **)
alloc_root(mem_root,sizeof(char *)*(result->count+1))))
return 0;
List_iterator<String> it(*src);
for (uint i=0; i<result->count; i++)
result->type_names[i]= strdup_root(mem_root, (it++)->c_ptr());
result->type_names[result->count]= 0;
}
return result;
}
int int
sp_head::create(THD *thd) sp_head::create(THD *thd)
{ {
...@@ -464,6 +450,21 @@ sp_head::destroy() ...@@ -464,6 +450,21 @@ sp_head::destroy()
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
Field *
sp_head::make_field(uint max_length, const char *name, TABLE *dummy)
{
Field *field;
DBUG_ENTER("sp_head::make_field");
field= ::make_field((char *)0,
!m_returns_len ? max_length : m_returns_len,
(uchar *)"", 0, m_returns_pack, m_returns, m_returns_cs,
(enum Field::geometry_type)0, Field::NONE,
m_returns_typelib,
name ? name : (const char *)m_name.str, dummy);
DBUG_RETURN(field);
}
int int
sp_head::execute(THD *thd) sp_head::execute(THD *thd)
{ {
......
...@@ -84,6 +84,9 @@ public: ...@@ -84,6 +84,9 @@ public:
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
enum enum_field_types m_returns; // For FUNCTIONs only enum enum_field_types m_returns; // For FUNCTIONs only
CHARSET_INFO *m_returns_cs; // For FUNCTIONs only CHARSET_INFO *m_returns_cs; // For FUNCTIONs only
TYPELIB *m_returns_typelib; // For FUNCTIONs only
uint m_returns_len; // For FUNCTIONs only
uint m_returns_pack; // For FUNCTIONs only
my_bool m_has_return; // For FUNCTIONs only my_bool m_has_return; // For FUNCTIONs only
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
my_bool m_multi_results; // TRUE if a procedure with SELECT(s) my_bool m_multi_results; // TRUE if a procedure with SELECT(s)
...@@ -96,7 +99,6 @@ public: ...@@ -96,7 +99,6 @@ public:
LEX_STRING m_db; LEX_STRING m_db;
LEX_STRING m_name; LEX_STRING m_name;
LEX_STRING m_params; LEX_STRING m_params;
LEX_STRING m_retstr; // For FUNCTIONs only
LEX_STRING m_body; LEX_STRING m_body;
LEX_STRING m_defstr; LEX_STRING m_defstr;
LEX_STRING m_definer_user; LEX_STRING m_definer_user;
...@@ -105,8 +107,7 @@ public: ...@@ -105,8 +107,7 @@ public:
longlong m_modified; longlong m_modified;
HASH m_sptabs; /* Merged table lists */ HASH m_sptabs; /* Merged table lists */
// Pointers set during parsing // Pointers set during parsing
uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end, uchar *m_param_begin, *m_param_end, *m_body_begin;
*m_body_begin;
static void * static void *
operator new(size_t size); operator new(size_t size);
...@@ -124,6 +125,9 @@ public: ...@@ -124,6 +125,9 @@ public:
void void
init_strings(THD *thd, LEX *lex, sp_name *name); init_strings(THD *thd, LEX *lex, sp_name *name);
TYPELIB *
create_typelib(List<String> *src);
int int
create(THD *thd); create(THD *thd);
...@@ -197,10 +201,7 @@ public: ...@@ -197,10 +201,7 @@ public:
char *create_string(THD *thd, ulong *lenp); char *create_string(THD *thd, ulong *lenp);
inline Item_result result() Field *make_field(uint max_length, const char *name, TABLE *dummy);
{
return sp_map_result_type(m_returns);
}
void set_info(char *definer, uint definerlen, void set_info(char *definer, uint definerlen,
longlong created, longlong modified, longlong created, longlong modified,
......
...@@ -5291,9 +5291,6 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5291,9 +5291,6 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{ {
register create_field *new_field; register create_field *new_field;
LEX *lex= thd->lex; LEX *lex= thd->lex;
uint allowed_type_modifier=0;
uint sign_len;
ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
DBUG_ENTER("add_field_to_list"); DBUG_ENTER("add_field_to_list");
if (strlen(field_name) > NAME_LEN) if (strlen(field_name) > NAME_LEN)
...@@ -5355,8 +5352,37 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5355,8 +5352,37 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (!(new_field=new create_field())) if (!(new_field= new_create_field(thd, field_name, type, length, decimals,
type_modifier, default_value, on_update_value,
comment, change, interval_list, cs, uint_geom_type)))
DBUG_RETURN(1); DBUG_RETURN(1);
lex->create_list.push_back(new_field);
lex->last_field=new_field;
DBUG_RETURN(0);
}
/*****************************************************************************
** Create field definition for create
** Return 0 on failure, otherwise return create_field instance
******************************************************************************/
create_field *
new_create_field(THD *thd, char *field_name, enum_field_types type,
char *length, char *decimals,
uint type_modifier,
Item *default_value, Item *on_update_value,
LEX_STRING *comment,
char *change, List<String> *interval_list, CHARSET_INFO *cs,
uint uint_geom_type)
{
register create_field *new_field;
uint sign_len, allowed_type_modifier=0;
ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
DBUG_ENTER("new_create_field");
if (!(new_field=new create_field()))
DBUG_RETURN(NULL);
new_field->field=0; new_field->field=0;
new_field->field_name=field_name; new_field->field_name=field_name;
new_field->def= default_value; new_field->def= default_value;
...@@ -5428,7 +5454,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5428,7 +5454,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->length >= new_field->decimals) new_field->length >= new_field->decimals)
break; break;
my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
DBUG_RETURN(1); DBUG_RETURN(NULL);
case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VARCHAR:
/* /*
Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
...@@ -5451,7 +5477,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5451,7 +5477,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{ {
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0),
field_name); /* purecov: inspected */ field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(NULL);
} }
new_field->def=0; new_field->def=0;
} }
...@@ -5471,7 +5497,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5471,7 +5497,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if (tmp_length > PRECISION_FOR_DOUBLE) if (tmp_length > PRECISION_FOR_DOUBLE)
{ {
my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
DBUG_RETURN(1); DBUG_RETURN(NULL);
} }
else if (tmp_length > PRECISION_FOR_FLOAT) else if (tmp_length > PRECISION_FOR_FLOAT)
{ {
...@@ -5568,7 +5594,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5568,7 +5594,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if (interval_list->elements > sizeof(longlong)*8) if (interval_list->elements > sizeof(longlong)*8)
{ {
my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */ my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(NULL);
} }
new_field->pack_length= (interval_list->elements + 7) / 8; new_field->pack_length= (interval_list->elements + 7) / 8;
if (new_field->pack_length > 4) if (new_field->pack_length > 4)
...@@ -5609,7 +5635,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5609,7 +5635,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{ {
my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name, my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), field_name,
MAX_BIT_FIELD_LENGTH); MAX_BIT_FIELD_LENGTH);
DBUG_RETURN(1); DBUG_RETURN(NULL);
} }
new_field->pack_length= (new_field->length + 7) / 8; new_field->pack_length= (new_field->length + 7) / 8;
break; break;
...@@ -5628,17 +5654,15 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, ...@@ -5628,17 +5654,15 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{ {
my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0),
field_name, max_field_charlength); /* purecov: inspected */ field_name, max_field_charlength); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */ DBUG_RETURN(NULL);
} }
type_modifier&= AUTO_INCREMENT_FLAG; type_modifier&= AUTO_INCREMENT_FLAG;
if ((~allowed_type_modifier) & type_modifier) if ((~allowed_type_modifier) & type_modifier)
{ {
my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
DBUG_RETURN(1); DBUG_RETURN(NULL);
} }
lex->create_list.push_back(new_field); DBUG_RETURN(new_field);
lex->last_field=new_field;
DBUG_RETURN(0);
} }
......
...@@ -424,6 +424,173 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval, ...@@ -424,6 +424,173 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
} }
/*
Prepare a create_table instance for packing
SYNOPSIS
prepare_create_field()
sql_field field to prepare for packing
blob_columns count for BLOBs
timestamps count for timestamps
table_flags table flags
DESCRIPTION
This function prepares a create_field instance.
Fields such as pack_flag are valid after this call.
RETURN VALUES
0 ok
1 Error
*/
int prepare_create_field(create_field *sql_field,
uint &blob_columns,
int &timestamps, int &timestamps_with_niladic,
uint table_flags)
{
DBUG_ENTER("prepare_field");
{
/* This code came from mysql_prepare_table.
Indent preserved to make patching easier */
DBUG_ASSERT(sql_field->charset);
switch (sql_field->sql_type) {
case FIELD_TYPE_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_LONG_BLOB:
sql_field->pack_flag=FIELDFLAG_BLOB |
pack_length_to_packflag(sql_field->pack_length -
portable_sizeof_char_ptr);
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->length=8; // Unireg field length
sql_field->unireg_check=Field::BLOB_FIELD;
blob_columns++;
break;
case FIELD_TYPE_GEOMETRY:
#ifdef HAVE_SPATIAL
if (!(table_flags & HA_CAN_GEOMETRY))
{
my_printf_error(ER_CHECK_NOT_IMPLEMENTED, ER(ER_CHECK_NOT_IMPLEMENTED),
MYF(0), "GEOMETRY");
DBUG_RETURN(1);
}
sql_field->pack_flag=FIELDFLAG_GEOM |
pack_length_to_packflag(sql_field->pack_length -
portable_sizeof_char_ptr);
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->length=8; // Unireg field length
sql_field->unireg_check=Field::BLOB_FIELD;
blob_columns++;
break;
#else
my_printf_error(ER_FEATURE_DISABLED,ER(ER_FEATURE_DISABLED), MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
DBUG_RETURN(1);
#endif /*HAVE_SPATIAL*/
case MYSQL_TYPE_VARCHAR:
#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
if (table_flags & HA_NO_VARCHAR)
{
/* convert VARCHAR to CHAR because handler is not yet up to date */
sql_field->sql_type= MYSQL_TYPE_VAR_STRING;
sql_field->pack_length= calc_pack_length(sql_field->sql_type,
(uint) sql_field->length);
if ((sql_field->length / sql_field->charset->mbmaxlen) >
MAX_FIELD_CHARLENGTH)
{
my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH);
DBUG_RETURN(1);
}
}
#endif
/* fall through */
case FIELD_TYPE_STRING:
sql_field->pack_flag=0;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
break;
case FIELD_TYPE_ENUM:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_INTERVAL;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::INTERVAL_FIELD;
check_duplicates_in_interval("ENUM",sql_field->field_name,
sql_field->interval,
sql_field->charset);
break;
case FIELD_TYPE_SET:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_BITFIELD;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::BIT_FIELD;
check_duplicates_in_interval("SET",sql_field->field_name,
sql_field->interval,
sql_field->charset);
break;
case FIELD_TYPE_DATE: // Rest of string types
case FIELD_TYPE_NEWDATE:
case FIELD_TYPE_TIME:
case FIELD_TYPE_DATETIME:
case FIELD_TYPE_NULL:
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
break;
case FIELD_TYPE_BIT:
if (!(table_flags & HA_CAN_BIT_FIELD))
{
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "BIT FIELD");
DBUG_RETURN(1);
}
sql_field->pack_flag= FIELDFLAG_NUMBER;
break;
case FIELD_TYPE_NEWDECIMAL:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
(sql_field->flags & UNSIGNED_FLAG ? 0 :
FIELDFLAG_DECIMAL) |
(sql_field->flags & ZEROFILL_FLAG ?
FIELDFLAG_ZEROFILL : 0) |
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
case FIELD_TYPE_TIMESTAMP:
/* We should replace old TIMESTAMP fields with their newer analogs */
if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
{
if (!timestamps)
{
sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
timestamps_with_niladic++;
}
else
sql_field->unireg_check= Field::NONE;
}
else if (sql_field->unireg_check != Field::NONE)
timestamps_with_niladic++;
timestamps++;
/* fall-through */
default:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
(sql_field->flags & UNSIGNED_FLAG ? 0 :
FIELDFLAG_DECIMAL) |
(sql_field->flags & ZEROFILL_FLAG ?
FIELDFLAG_ZEROFILL : 0) |
f_settype((uint) sql_field->sql_type) |
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
}
if (!(sql_field->flags & NOT_NULL_FLAG))
sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
}
DBUG_RETURN(0);
}
/* /*
Preparation for table creation Preparation for table creation
...@@ -683,142 +850,17 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, ...@@ -683,142 +850,17 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
{ {
DBUG_ASSERT(sql_field->charset); DBUG_ASSERT(sql_field->charset);
switch (sql_field->sql_type) { if (prepare_create_field(sql_field, blob_columns,
case FIELD_TYPE_BLOB: timestamps, timestamps_with_niladic,
case FIELD_TYPE_MEDIUM_BLOB: file->table_flags()))
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_LONG_BLOB:
sql_field->pack_flag=FIELDFLAG_BLOB |
pack_length_to_packflag(sql_field->pack_length -
portable_sizeof_char_ptr);
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->length=8; // Unireg field length
sql_field->unireg_check=Field::BLOB_FIELD;
blob_columns++;
create_info->varchar= 1;
break;
case FIELD_TYPE_GEOMETRY:
#ifdef HAVE_SPATIAL
if (!(file->table_flags() & HA_CAN_GEOMETRY))
{
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
DBUG_RETURN(-1); DBUG_RETURN(-1);
} if (sql_field->sql_type == FIELD_TYPE_BLOB ||
sql_field->pack_flag=FIELDFLAG_GEOM | sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB ||
pack_length_to_packflag(sql_field->pack_length - sql_field->sql_type == FIELD_TYPE_TINY_BLOB ||
portable_sizeof_char_ptr); sql_field->sql_type == FIELD_TYPE_LONG_BLOB ||
if (sql_field->charset->state & MY_CS_BINSORT) sql_field->sql_type == FIELD_TYPE_GEOMETRY ||
sql_field->pack_flag|=FIELDFLAG_BINARY; sql_field->sql_type == MYSQL_TYPE_VARCHAR)
sql_field->length=8; // Unireg field length
sql_field->unireg_check=Field::BLOB_FIELD;
blob_columns++;
create_info->varchar= 1;
break;
#else
my_error(ER_FEATURE_DISABLED, MYF(0),
sym_group_geom.name, sym_group_geom.needed_define);
DBUG_RETURN(-1);
#endif /*HAVE_SPATIAL*/
case MYSQL_TYPE_VARCHAR:
#ifndef QQ_ALL_HANDLERS_SUPPORT_VARCHAR
if (file->table_flags() & HA_NO_VARCHAR)
{
/* convert VARCHAR to CHAR because handler is not yet up to date */
sql_field->sql_type= MYSQL_TYPE_VAR_STRING;
sql_field->pack_length= calc_pack_length(sql_field->sql_type,
(uint) sql_field->length);
if ((sql_field->length / sql_field->charset->mbmaxlen) >
MAX_FIELD_CHARLENGTH)
{
my_printf_error(ER_TOO_BIG_FIELDLENGTH, ER(ER_TOO_BIG_FIELDLENGTH),
MYF(0), sql_field->field_name, MAX_FIELD_CHARLENGTH);
DBUG_RETURN(-1);
}
}
else
#endif
create_info->varchar= 1; create_info->varchar= 1;
/* fall through */
case MYSQL_TYPE_STRING:
sql_field->pack_flag=0;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|= FIELDFLAG_BINARY;
break;
case FIELD_TYPE_ENUM:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_INTERVAL;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::INTERVAL_FIELD;
check_duplicates_in_interval("ENUM",sql_field->field_name,
sql_field->interval,
sql_field->charset);
break;
case FIELD_TYPE_SET:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_BITFIELD;
if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::BIT_FIELD;
check_duplicates_in_interval("SET",sql_field->field_name,
sql_field->interval,
sql_field->charset);
break;
case FIELD_TYPE_DATE: // Rest of string types
case FIELD_TYPE_NEWDATE:
case FIELD_TYPE_TIME:
case FIELD_TYPE_DATETIME:
case FIELD_TYPE_NULL:
sql_field->pack_flag=f_settype((uint) sql_field->sql_type);
break;
case FIELD_TYPE_BIT:
if (!(file->table_flags() & HA_CAN_BIT_FIELD))
{
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "BIT FIELD");
DBUG_RETURN(-1);
}
sql_field->pack_flag= FIELDFLAG_NUMBER;
break;
case FIELD_TYPE_NEWDECIMAL:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
(sql_field->flags & UNSIGNED_FLAG ? 0 :
FIELDFLAG_DECIMAL) |
(sql_field->flags & ZEROFILL_FLAG ?
FIELDFLAG_ZEROFILL : 0) |
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
case FIELD_TYPE_TIMESTAMP:
/* We should replace old TIMESTAMP fields with their newer analogs */
if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
{
if (!timestamps)
{
sql_field->unireg_check= Field::TIMESTAMP_DNUN_FIELD;
timestamps_with_niladic++;
}
else
sql_field->unireg_check= Field::NONE;
}
else if (sql_field->unireg_check != Field::NONE)
timestamps_with_niladic++;
timestamps++;
/* fall-through */
default:
sql_field->pack_flag=(FIELDFLAG_NUMBER |
(sql_field->flags & UNSIGNED_FLAG ? 0 :
FIELDFLAG_DECIMAL) |
(sql_field->flags & ZEROFILL_FLAG ?
FIELDFLAG_ZEROFILL : 0) |
f_settype((uint) sql_field->sql_type) |
(sql_field->decimals << FIELDFLAG_DEC_SHIFT));
break;
}
if (!(sql_field->flags & NOT_NULL_FLAG))
sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL;
if (sql_field->flags & NO_DEFAULT_VALUE_FLAG)
sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT;
sql_field->offset= pos; sql_field->offset= pos;
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
auto_increment++; auto_increment++;
...@@ -1585,6 +1627,8 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, ...@@ -1585,6 +1627,8 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
((Item_field *)item)->field : ((Item_field *)item)->field :
(Field*) 0)))) (Field*) 0))))
DBUG_RETURN(0); DBUG_RETURN(0);
if (item->maybe_null)
cr_field->flags &= ~NOT_NULL_FLAG;
extra_fields->push_back(cr_field); extra_fields->push_back(cr_field);
} }
/* /*
......
...@@ -1370,19 +1370,37 @@ create_function_tail: ...@@ -1370,19 +1370,37 @@ create_function_tail:
RETURNS_SYM RETURNS_SYM
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead; lex->charset= NULL;
lex->length= lex->dec= NULL;
sp->m_returns_begin= lex->tok_start; lex->interval_list.empty();
sp->m_returns_cs= lex->charset= NULL; lex->type= 0;
} }
type type
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
LEX_STRING cmt = { 0, 0 };
create_field *new_field;
uint unused1= 0;
int unused2= 0;
if (!(new_field= new_create_field(YYTHD, "", (enum enum_field_types)$8,
lex->length, lex->dec, lex->type,
(Item *)0, (Item *) 0, &cmt, 0, &lex->interval_list,
(lex->charset ? lex->charset : default_charset_info),
lex->uint_geom_type)))
YYABORT;
if (prepare_create_field(new_field, unused1, unused2, unused2, 0))
YYABORT;
sp->m_returns= new_field->sql_type;
sp->m_returns_cs= new_field->charset;
sp->m_returns_len= new_field->length;
sp->m_returns_pack= new_field->pack_flag;
sp->m_returns_typelib=
sp->create_typelib(&new_field->interval_list);
sp->m_returns_end= lex->tok_start;
sp->m_returns= (enum enum_field_types)$8;
sp->m_returns_cs= lex->charset;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
} }
sp_c_chistics sp_c_chistics
......
...@@ -695,6 +695,7 @@ static bool make_empty_rec(File file,enum db_type table_type, ...@@ -695,6 +695,7 @@ static bool make_empty_rec(File file,enum db_type table_type,
field->interval, field->interval,
field->field_name, field->field_name,
&table); &table);
DBUG_ASSERT(regfield);
if (!(field->flags & NOT_NULL_FLAG)) if (!(field->flags & NOT_NULL_FLAG))
null_count++; null_count++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment