diff --git a/sql/sp.h b/sql/sp.h index eb3291f..149077f 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -45,7 +45,8 @@ enum stored_procedure_type TYPE_ENUM_FUNCTION=1, TYPE_ENUM_PROCEDURE=2, TYPE_ENUM_TRIGGER=3, - TYPE_ENUM_PROXY=4 + TYPE_ENUM_PROXY=4, + TYPE_ENUM_TABLE=5 }; /* Tells what SP_DEFAULT_ACCESS should be mapped to */ diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8efeeab..09920c5 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2360,7 +2360,34 @@ void sp_head::recursion_level_error(THD *thd) return FALSE; } - +bool +sp_head::fill_resultset_definition(THD *thd, List *create_list) +{ + List_iterator_fast it(*create_list); + Create_field *field; + while ((field= it++)) + { + Create_field *new_field = field->clone(thd->mem_root); + switch (new_field->sql_type) { + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + new_field->charset= &my_charset_bin; + default: break; + } + if (!new_field->charset) + new_field->charset= default_charset_info; + if (!new_field->charset) + new_field->charset= system_charset_info; + if (new_field->interval_list.elements) + new_field->interval= create_typelib(thd->mem_root, new_field, &new_field->interval_list); + sp_prepare_create_field(thd, new_field); + if(m_cols_list.push_back(new_field, thd->mem_root)) + return TRUE; + } +} int sp_head::new_cont_backpatch(sp_instr_opt_meta *i) { diff --git a/sql/sp_head.h b/sql/sp_head.h index dbdb957..7246052 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -182,6 +182,7 @@ class sp_head :private Query_arena uint m_flags; // Boolean attributes of a stored routine Create_field m_return_field_def; /**< This is used for FUNCTIONs only. */ + List m_cols_list; /**< Used for TABLE FUNCTIONs only. */ const char *m_tmp_query; ///< Temporary pointer to sub query string st_sp_chistics *m_chistics; @@ -196,7 +197,7 @@ class sp_head :private Query_arena LEX_STRING m_defstr; LEX_STRING m_definer_user; LEX_STRING m_definer_host; - + LEX_STRING m_table_alias; /** Is this routine being executed? */ @@ -420,7 +421,7 @@ class sp_head :private Query_arena bool fill_field_definition(THD *thd, LEX *lex, enum enum_field_types field_type, Create_field *field_def); - + bool fill_resultset_definition(THD *thd, List *create_list); void set_info(longlong created, longlong modified, st_sp_chistics *chistics, ulonglong sql_mode); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index cf933e0b..1dd2ad2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1202,6 +1202,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ENCLOSED %token END /* SQL-2003-R */ %token ENDS_SYM +%token END_SYM %token END_OF_INPUT /* INTERNAL */ %token ENGINES_SYM %token ENGINE_SYM @@ -1965,7 +1966,7 @@ END_OF_INPUT %type sp_cond sp_hcond sqlstate signal_value opt_signal_value %type sp_decls sp_decl %type sp_cursor_stmt -%type sp_name +%type sp_name table_function %type sp_block_content %type sp_param_name_and_type %type sp_opt_inout @@ -6629,22 +6630,33 @@ attribute: } ; - type_with_opt_collate: - field_type opt_collate - { - $$= $1; + field_type opt_collate + { + $$= $1; - if ($2) + if ($2) + { + if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))) + MYSQL_YYABORT; + } + Lex->set_last_field_type($1); + } + | TABLE_SYM ident '(' field_list ')' { - if (!(Lex->charset= merge_charset_and_collation(Lex->charset, $2))) + Lex->sphead->m_table_alias= $2; + // table functions, we need to store the return types + Lex->sphead->m_type= TYPE_ENUM_TABLE; + if(Lex->sphead->fill_resultset_definition(thd, &Lex->alter_info.create_list)) + MYSQL_YYABORT; + if (Lex->sphead->m_cols_list.is_empty()) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; + } } - Lex->set_last_field_type($1); - } ; - now_or_signed_literal: NOW_SYM opt_default_time_precision { @@ -10873,6 +10885,25 @@ table_factor: $$= $3; } } + | table_function '(' table_function_args ')' opt_table_alias + { + LEX *lex=Lex; + SELECT_LEX *sel= lex->current_select; + SELECT_LEX_UNIT *unit= sel->master_unit(); + lex->current_select= sel= unit->outer_select(); + Table_ident *ti= new Table_ident(unit); + if (ti == NULL) + MYSQL_YYABORT; + unit->spname= $1; + unit->sparg_list= unit->item_list; + unit->item_list.empty(); + if (!($$= sel->add_table_to_list(lex->thd, + ti, $5, 0, + TL_READ))) + MYSQL_YYABORT; + sel->add_joined_table($$); + lex->pop_context(); + } ; /* @@ -11012,6 +11043,38 @@ select_derived2: opt_select_from ; +table_function: + sp_name + { + LEX *lex= Lex; + lex->derived_tables|= DERIVED_SUBQUERY; + if (!lex->expr_allows_subselect || + lex->sql_command == (int)SQLCOM_PURGE) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } + if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || + mysql_new_select(lex, 1)) + MYSQL_YYABORT; + mysql_init_select(lex); + lex->current_select->linkage= TABLE_FUNCTION_TYPE; + lex->current_select->parsing_place= NO_MATTER; + sp_add_used_routine(lex, YYTHD, $1, TYPE_ENUM_FUNCTION); + $$= $1; + } + ; + +table_function_args: + /* empty */ + | '(' table_function_arg_items ')' + ; + +table_function_arg_items: + table_function_arg_items ',' select_item + | select_item + ; + get_select_lex: /* Empty */ { $$= Select; } ; @@ -16285,9 +16348,13 @@ sf_tail: } type_with_opt_collate /* $11 */ { /* $12 */ - if (Lex->sphead->fill_field_definition(thd, Lex, $11, - Lex->last_field)) - MYSQL_YYABORT; + if (!(Lex->sphead->m_type== TYPE_ENUM_TABLE)) + { + Lex->sphead->m_type = TYPE_ENUM_FUNCTION; + if (Lex->sphead->fill_field_definition(thd, Lex, $11, + Lex->last_field)) + MYSQL_YYABORT; + } } sp_c_chistics /* $13 */ { /* $14 */ @@ -16306,12 +16373,13 @@ sf_tail: lex->sql_command= SQLCOM_CREATE_SPFUNCTION; sp->set_stmt_end(thd); - if (!(sp->m_flags & sp_head::HAS_RETURN)) + if (!(sp->m_flags & sp_head::HAS_RETURN) && !(Lex->sphead->m_type== TYPE_ENUM_TABLE)) { my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); MYSQL_YYABORT; } - if (is_native_function(thd, & sp->m_name)) + if ((Lex->sphead->m_type == TYPE_ENUM_FUNCTION) && + is_native_function(thd, & sp->m_name)) { /* This warning will be printed when @@ -16451,7 +16519,7 @@ begin_or_start: BEGIN_SYM {} | START_SYM {} ; - + opt_join_or_resume: /* nothing */ { Lex->xa_opt=XA_NONE; } | JOIN_SYM { Lex->xa_opt=XA_JOIN; }