diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 4373925..58be47e 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -2866,3 +2866,9 @@ SELECT @msg; DROP FUNCTION f1; DROP FUNCTION f2; DROP TABLE t1; +CREATE FUNCTION f1(a INT, b VARCHAR(11)) +RETURNS TABLE t1(id INT, name VARCHAR(11)) +BEGIN +INSERT INTO t1 SELECT id, name FROM t2 WHERE id = a; +END| +ERROR 42000: This version of MariaDB doesn't yet support '%s' near 'Table functions' at line 3 diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index c1a21c8..580f2b4 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -3845,3 +3845,14 @@ SELECT @msg; DROP FUNCTION f1; DROP FUNCTION f2; DROP TABLE t1; + + +delimiter |; +--error 1064 +CREATE FUNCTION f1(a INT, b VARCHAR(11)) +RETURNS TABLE t1(id INT, name VARCHAR(11)) +BEGIN +INSERT INTO t1 SELECT id, name FROM t2 WHERE id = a; +END| + +DELIMITER ;| 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..f705930 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2360,6 +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..4b2fe31 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,6 +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,6 +422,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..d3d905b 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1731,7 +1731,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type text_string hex_or_bin_String opt_gconcat_separator -%type type_with_opt_collate int_type real_type field_type +%type type_with_opt_collate sf_type_with_opt_collate int_type real_type field_type %type spatial_type @@ -6644,7 +6644,25 @@ type_with_opt_collate: } ; - +sf_type_with_opt_collate: + type_with_opt_collate + { + $$ = $1; + } + | TABLE_SYM ident '(' field_list ')' + { + 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; + } + } + ; now_or_signed_literal: NOW_SYM opt_default_time_precision { @@ -16283,11 +16301,15 @@ sf_tail: lex->init_last_field(&lex->sphead->m_return_field_def, NULL, thd->variables.collation_database); } - type_with_opt_collate /* $11 */ + sf_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 */ @@ -16295,6 +16317,12 @@ sf_tail: Lex_input_stream *lip= YYLIP; lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); + + if (Lex->sphead->m_type== TYPE_ENUM_TABLE) //to be removed later. + { + my_parse_error(ER(ER_NOT_SUPPORTED_YET), "Table functions"); + MYSQL_YYABORT; + } } sp_proc_stmt /* $15 */ { @@ -16306,7 +16334,7 @@ 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;