summaryrefslogtreecommitdiffstats
path: root/sql/sp.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sql/sp.h674
1 files changed, 674 insertions, 0 deletions
diff --git a/sql/sp.h b/sql/sp.h
new file mode 100644
index 00000000..e92525e1
--- /dev/null
+++ b/sql/sp.h
@@ -0,0 +1,674 @@
+/* -*- C++ -*- */
+/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2009, 2020, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#ifndef _SP_H_
+#define _SP_H_
+
+#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
+#include "sql_string.h" // LEX_STRING
+#include "sql_cmd.h"
+#include "mdl.h"
+
+class Field;
+class Open_tables_backup;
+class Open_tables_state;
+class Query_arena;
+class Query_tables_list;
+class Sroutine_hash_entry;
+class THD;
+class sp_cache;
+class sp_head;
+class sp_package;
+class sp_pcontext;
+class sp_name;
+class Database_qualified_name;
+struct st_sp_chistics;
+class Stored_program_creation_ctx;
+struct LEX;
+struct TABLE;
+struct TABLE_LIST;
+typedef struct st_hash HASH;
+template <typename T> class SQL_I_List;
+
+/*
+ Values for the type enum. This reflects the order of the enum declaration
+ in the CREATE TABLE command.
+ See also storage/perfschema/my_thread.h
+*/
+enum enum_sp_type
+{
+ SP_TYPE_FUNCTION=1,
+ SP_TYPE_PROCEDURE=2,
+ SP_TYPE_PACKAGE=3,
+ SP_TYPE_PACKAGE_BODY=4,
+ SP_TYPE_TRIGGER=5,
+ SP_TYPE_EVENT=6,
+};
+
+class Sp_handler
+{
+ bool sp_resolve_package_routine_explicit(THD *thd,
+ sp_head *caller,
+ sp_name *name,
+ const Sp_handler **pkg_routine_hndlr,
+ Database_qualified_name *pkgname)
+ const;
+ bool sp_resolve_package_routine_implicit(THD *thd,
+ sp_head *caller,
+ sp_name *name,
+ const Sp_handler **pkg_routine_hndlr,
+ Database_qualified_name *pkgname)
+ const;
+protected:
+ int db_find_routine_aux(THD *thd, const Database_qualified_name *name,
+ TABLE *table) const;
+ int db_find_routine(THD *thd, const Database_qualified_name *name,
+ sp_head **sphp) const;
+ int db_find_and_cache_routine(THD *thd,
+ const Database_qualified_name *name,
+ sp_head **sp) const;
+ int db_load_routine(THD *thd, const Database_qualified_name *name,
+ sp_head **sphp,
+ sql_mode_t sql_mode,
+ const LEX_CSTRING &params,
+ const LEX_CSTRING &returns,
+ const LEX_CSTRING &body,
+ const st_sp_chistics &chistics,
+ const AUTHID &definer,
+ longlong created, longlong modified,
+ sp_package *parent,
+ Stored_program_creation_ctx *creation_ctx) const;
+ int sp_drop_routine_internal(THD *thd,
+ const Database_qualified_name *name,
+ TABLE *table) const;
+
+ sp_head *sp_clone_and_link_routine(THD *thd,
+ const Database_qualified_name *name,
+ sp_head *sp) const;
+ int sp_cache_package_routine(THD *thd,
+ const LEX_CSTRING &pkgname_cstr,
+ const Database_qualified_name *name,
+ bool lookup_only, sp_head **sp) const;
+ int sp_cache_package_routine(THD *thd,
+ const Database_qualified_name *name,
+ bool lookup_only, sp_head **sp) const;
+ sp_head *sp_find_package_routine(THD *thd,
+ const LEX_CSTRING pkgname_str,
+ const Database_qualified_name *name,
+ bool cache_only) const;
+ sp_head *sp_find_package_routine(THD *thd,
+ const Database_qualified_name *name,
+ bool cache_only) const;
+public: // TODO: make it private or protected
+ virtual int sp_find_and_drop_routine(THD *thd, TABLE *table,
+ const Database_qualified_name *name)
+ const;
+
+public:
+ virtual ~Sp_handler() {}
+ static const Sp_handler *handler(enum enum_sql_command cmd);
+ static const Sp_handler *handler(enum_sp_type type);
+ static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns);
+ /*
+ Return a handler only those SP objects that store
+ definitions in the mysql.proc system table
+ */
+ static const Sp_handler *handler_mysql_proc(enum_sp_type type)
+ {
+ const Sp_handler *sph= handler(type);
+ return sph ? sph->sp_handler_mysql_proc() : NULL;
+ }
+
+ static bool eq_routine_name(const LEX_CSTRING &name1,
+ const LEX_CSTRING &name2)
+ {
+ return system_charset_info->strnncoll(name1.str, name1.length,
+ name2.str, name2.length) == 0;
+ }
+ const char *type_str() const { return type_lex_cstring().str; }
+ virtual const char *show_create_routine_col1_caption() const
+ {
+ DBUG_ASSERT(0);
+ return "";
+ }
+ virtual const char *show_create_routine_col3_caption() const
+ {
+ DBUG_ASSERT(0);
+ return "";
+ }
+ virtual const Sp_handler *package_routine_handler() const
+ {
+ return this;
+ }
+ virtual enum_sp_type type() const= 0;
+ virtual LEX_CSTRING type_lex_cstring() const= 0;
+ virtual LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
+ {
+ static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("???")};
+ DBUG_ASSERT(0);
+ return m_empty_body;
+ }
+ virtual MDL_key::enum_mdl_namespace get_mdl_type() const= 0;
+ virtual const Sp_handler *sp_handler_mysql_proc() const { return this; }
+ virtual sp_cache **get_cache(THD *) const { return NULL; }
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ virtual HASH *get_priv_hash() const { return NULL; }
+#endif
+ virtual ulong recursion_depth(THD *thd) const { return 0; }
+ /**
+ Return appropriate error about recursion limit reaching
+
+ @param thd Thread handle
+ @param sp SP routine
+
+ @remark For functions and triggers we return error about
+ prohibited recursion. For stored procedures we
+ return about reaching recursion limit.
+ */
+ virtual void recursion_level_error(THD *thd, const sp_head *sp) const
+ {
+ my_error(ER_SP_NO_RECURSION, MYF(0));
+ }
+ virtual bool add_instr_freturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont,
+ Item *item, LEX *lex) const;
+ virtual bool add_instr_preturn(THD *thd, sp_head *sp,
+ sp_pcontext *spcont) const;
+
+ void add_used_routine(Query_tables_list *prelocking_ctx,
+ Query_arena *arena,
+ const Database_qualified_name *name) const;
+
+ bool sp_resolve_package_routine(THD *thd,
+ sp_head *caller,
+ sp_name *name,
+ const Sp_handler **pkg_routine_handler,
+ Database_qualified_name *pkgname) const;
+ virtual sp_head *sp_find_routine(THD *thd,
+ const Database_qualified_name *name,
+ bool cache_only) const;
+ virtual int sp_cache_routine(THD *thd, const Database_qualified_name *name,
+ bool lookup_only, sp_head **sp) const;
+
+ int sp_cache_routine_reentrant(THD *thd,
+ const Database_qualified_name *nm,
+ sp_head **sp) const;
+
+ bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const;
+ bool sp_show_create_routine(THD *thd,
+ const Database_qualified_name *name) const;
+
+ bool sp_create_routine(THD *thd, const sp_head *sp) const;
+
+ int sp_update_routine(THD *thd, const Database_qualified_name *name,
+ const st_sp_chistics *chistics) const;
+
+ int sp_drop_routine(THD *thd, const Database_qualified_name *name) const;
+
+ sp_head *sp_load_for_information_schema(THD *thd, TABLE *proc_table,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &name,
+ const LEX_CSTRING &params,
+ const LEX_CSTRING &returns,
+ sql_mode_t sql_mode,
+ bool *free_sp_head) const;
+
+ /*
+ Make a SHOW CREATE statement.
+ @retval true on error
+ @retval false on success
+ */
+ virtual bool show_create_sp(THD *thd, String *buf,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &name,
+ const LEX_CSTRING &params,
+ const LEX_CSTRING &returns,
+ const LEX_CSTRING &body,
+ const st_sp_chistics &chistics,
+ const AUTHID &definer,
+ const DDL_options_st ddl_options,
+ sql_mode_t sql_mode) const;
+
+};
+
+
+class Sp_handler_procedure: public Sp_handler
+{
+public:
+ enum_sp_type type() const { return SP_TYPE_PROCEDURE; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= { STRING_WITH_LEN("PROCEDURE")};
+ return m_type_str;
+ }
+ LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const;
+ const char *show_create_routine_col1_caption() const
+ {
+ return "Procedure";
+ }
+ const char *show_create_routine_col3_caption() const
+ {
+ return "Create Procedure";
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ return MDL_key::PROCEDURE;
+ }
+ const Sp_handler *package_routine_handler() const;
+ sp_cache **get_cache(THD *) const;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ HASH *get_priv_hash() const;
+#endif
+ ulong recursion_depth(THD *thd) const;
+ void recursion_level_error(THD *thd, const sp_head *sp) const;
+ bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const;
+};
+
+
+class Sp_handler_package_procedure: public Sp_handler_procedure
+{
+public:
+ int sp_cache_routine(THD *thd, const Database_qualified_name *name,
+ bool lookup_only, sp_head **sp) const
+ {
+ return sp_cache_package_routine(thd, name, lookup_only, sp);
+ }
+ sp_head *sp_find_routine(THD *thd,
+ const Database_qualified_name *name,
+ bool cache_only) const
+ {
+ return sp_find_package_routine(thd, name, cache_only);
+ }
+};
+
+
+class Sp_handler_function: public Sp_handler
+{
+public:
+ enum_sp_type type() const { return SP_TYPE_FUNCTION; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= { STRING_WITH_LEN("FUNCTION")};
+ return m_type_str;
+ }
+ LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const;
+ const char *show_create_routine_col1_caption() const
+ {
+ return "Function";
+ }
+ const char *show_create_routine_col3_caption() const
+ {
+ return "Create Function";
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ return MDL_key::FUNCTION;
+ }
+ const Sp_handler *package_routine_handler() const;
+ sp_cache **get_cache(THD *) const;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ HASH *get_priv_hash() const;
+#endif
+ bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont,
+ Item *item, LEX *lex) const;
+};
+
+
+class Sp_handler_package_function: public Sp_handler_function
+{
+public:
+ int sp_cache_routine(THD *thd, const Database_qualified_name *name,
+ bool lookup_only, sp_head **sp) const
+ {
+ return sp_cache_package_routine(thd, name, lookup_only, sp);
+ }
+ sp_head *sp_find_routine(THD *thd,
+ const Database_qualified_name *name,
+ bool cache_only) const
+ {
+ return sp_find_package_routine(thd, name, cache_only);
+ }
+};
+
+
+class Sp_handler_package: public Sp_handler
+{
+public:
+ bool show_create_sp(THD *thd, String *buf,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &name,
+ const LEX_CSTRING &params,
+ const LEX_CSTRING &returns,
+ const LEX_CSTRING &body,
+ const st_sp_chistics &chistics,
+ const AUTHID &definer,
+ const DDL_options_st ddl_options,
+ sql_mode_t sql_mode) const;
+};
+
+
+class Sp_handler_package_spec: public Sp_handler_package
+{
+public: // TODO: make it private or protected
+ int sp_find_and_drop_routine(THD *thd, TABLE *table,
+ const Database_qualified_name *name)
+ const;
+public:
+ enum_sp_type type() const { return SP_TYPE_PACKAGE; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE")};
+ return m_type_str;
+ }
+ LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
+ {
+ static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("BEGIN END")};
+ return m_empty_body;
+ }
+ const char *show_create_routine_col1_caption() const
+ {
+ return "Package";
+ }
+ const char *show_create_routine_col3_caption() const
+ {
+ return "Create Package";
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ return MDL_key::PACKAGE_BODY;
+ }
+ sp_cache **get_cache(THD *) const;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ HASH *get_priv_hash() const;
+#endif
+};
+
+
+class Sp_handler_package_body: public Sp_handler_package
+{
+public:
+ enum_sp_type type() const { return SP_TYPE_PACKAGE_BODY; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE BODY")};
+ return m_type_str;
+ }
+ LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
+ {
+ static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("BEGIN END")};
+ return m_empty_body;
+ }
+ const char *show_create_routine_col1_caption() const
+ {
+ return "Package body";
+ }
+ const char *show_create_routine_col3_caption() const
+ {
+ return "Create Package Body";
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ return MDL_key::PACKAGE_BODY;
+ }
+ sp_cache **get_cache(THD *) const;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ HASH *get_priv_hash() const;
+#endif
+};
+
+
+class Sp_handler_trigger: public Sp_handler
+{
+public:
+ enum_sp_type type() const { return SP_TYPE_TRIGGER; }
+ LEX_CSTRING type_lex_cstring() const
+ {
+ static LEX_CSTRING m_type_str= { STRING_WITH_LEN("TRIGGER")};
+ return m_type_str;
+ }
+ MDL_key::enum_mdl_namespace get_mdl_type() const
+ {
+ DBUG_ASSERT(0);
+ return MDL_key::TRIGGER;
+ }
+ const Sp_handler *sp_handler_mysql_proc() const { return NULL; }
+};
+
+
+extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_package_spec sp_handler_package_spec;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_package_body sp_handler_package_body;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_package_function sp_handler_package_function;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_package_procedure sp_handler_package_procedure;
+extern MYSQL_PLUGIN_IMPORT Sp_handler_trigger sp_handler_trigger;
+
+
+inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)
+{
+ switch (cmd) {
+ case SQLCOM_CREATE_PROCEDURE:
+ case SQLCOM_ALTER_PROCEDURE:
+ case SQLCOM_DROP_PROCEDURE:
+ case SQLCOM_SHOW_PROC_CODE:
+ case SQLCOM_SHOW_CREATE_PROC:
+ case SQLCOM_SHOW_STATUS_PROC:
+ return &sp_handler_procedure;
+ case SQLCOM_CREATE_SPFUNCTION:
+ case SQLCOM_ALTER_FUNCTION:
+ case SQLCOM_DROP_FUNCTION:
+ case SQLCOM_SHOW_FUNC_CODE:
+ case SQLCOM_SHOW_CREATE_FUNC:
+ case SQLCOM_SHOW_STATUS_FUNC:
+ return &sp_handler_function;
+ case SQLCOM_CREATE_PACKAGE:
+ case SQLCOM_DROP_PACKAGE:
+ case SQLCOM_SHOW_CREATE_PACKAGE:
+ case SQLCOM_SHOW_STATUS_PACKAGE:
+ return &sp_handler_package_spec;
+ case SQLCOM_CREATE_PACKAGE_BODY:
+ case SQLCOM_DROP_PACKAGE_BODY:
+ case SQLCOM_SHOW_CREATE_PACKAGE_BODY:
+ case SQLCOM_SHOW_STATUS_PACKAGE_BODY:
+ case SQLCOM_SHOW_PACKAGE_BODY_CODE:
+ return &sp_handler_package_body;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+
+inline const Sp_handler *Sp_handler::handler(enum_sp_type type)
+{
+ switch (type) {
+ case SP_TYPE_PROCEDURE:
+ return &sp_handler_procedure;
+ case SP_TYPE_FUNCTION:
+ return &sp_handler_function;
+ case SP_TYPE_PACKAGE:
+ return &sp_handler_package_spec;
+ case SP_TYPE_PACKAGE_BODY:
+ return &sp_handler_package_body;
+ case SP_TYPE_TRIGGER:
+ return &sp_handler_trigger;
+ case SP_TYPE_EVENT:
+ break;
+ }
+ return NULL;
+}
+
+
+inline const Sp_handler *Sp_handler::handler(MDL_key::enum_mdl_namespace type)
+{
+ switch (type) {
+ case MDL_key::FUNCTION:
+ return &sp_handler_function;
+ case MDL_key::PROCEDURE:
+ return &sp_handler_procedure;
+ case MDL_key::PACKAGE_BODY:
+ return &sp_handler_package_body;
+ case MDL_key::BACKUP:
+ case MDL_key::SCHEMA:
+ case MDL_key::TABLE:
+ case MDL_key::TRIGGER:
+ case MDL_key::EVENT:
+ case MDL_key::USER_LOCK:
+ case MDL_key::NAMESPACE_END:
+ break;
+ }
+ return NULL;
+}
+
+
+/* Tells what SP_DEFAULT_ACCESS should be mapped to */
+#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
+
+// Return codes from sp_create_*, sp_drop_*, and sp_show_*:
+#define SP_OK 0
+#define SP_KEY_NOT_FOUND -1
+#define SP_OPEN_TABLE_FAILED -2
+#define SP_WRITE_ROW_FAILED -3
+#define SP_DELETE_ROW_FAILED -4
+#define SP_GET_FIELD_FAILED -5
+#define SP_PARSE_ERROR -6
+#define SP_INTERNAL_ERROR -7
+#define SP_NO_DB_ERROR -8
+#define SP_BAD_IDENTIFIER -9
+#define SP_BODY_TOO_LONG -10
+#define SP_FLD_STORE_FAILED -11
+
+/* DB storage of Stored PROCEDUREs and FUNCTIONs */
+enum
+{
+ MYSQL_PROC_FIELD_DB = 0,
+ MYSQL_PROC_FIELD_NAME,
+ MYSQL_PROC_MYSQL_TYPE,
+ MYSQL_PROC_FIELD_SPECIFIC_NAME,
+ MYSQL_PROC_FIELD_LANGUAGE,
+ MYSQL_PROC_FIELD_ACCESS,
+ MYSQL_PROC_FIELD_DETERMINISTIC,
+ MYSQL_PROC_FIELD_SECURITY_TYPE,
+ MYSQL_PROC_FIELD_PARAM_LIST,
+ MYSQL_PROC_FIELD_RETURNS,
+ MYSQL_PROC_FIELD_BODY,
+ MYSQL_PROC_FIELD_DEFINER,
+ MYSQL_PROC_FIELD_CREATED,
+ MYSQL_PROC_FIELD_MODIFIED,
+ MYSQL_PROC_FIELD_SQL_MODE,
+ MYSQL_PROC_FIELD_COMMENT,
+ MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT,
+ MYSQL_PROC_FIELD_COLLATION_CONNECTION,
+ MYSQL_PROC_FIELD_DB_COLLATION,
+ MYSQL_PROC_FIELD_BODY_UTF8,
+ MYSQL_PROC_FIELD_AGGREGATE,
+ MYSQL_PROC_FIELD_COUNT
+};
+
+/* Drop all routines in database 'db' */
+int
+sp_drop_db_routines(THD *thd, const char *db);
+
+/**
+ Acquires exclusive metadata lock on all stored routines in the
+ given database.
+
+ @param thd Thread handler
+ @param db Database name
+
+ @retval false Success
+ @retval true Failure
+ */
+bool lock_db_routines(THD *thd, const char *db);
+
+/**
+ Structure that represents element in the set of stored routines
+ used by statement or routine.
+*/
+
+class Sroutine_hash_entry
+{
+public:
+ /**
+ Metadata lock request for routine.
+ MDL_key in this request is also used as a key for set.
+ */
+ MDL_request mdl_request;
+ /**
+ Next element in list linking all routines in set. See also comments
+ for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
+ */
+ Sroutine_hash_entry *next;
+ /**
+ Uppermost view which directly or indirectly uses this routine.
+ 0 if routine is not used in view. Note that it also can be 0 if
+ statement uses routine both via view and directly.
+ */
+ TABLE_LIST *belong_to_view;
+ /**
+ This is for prepared statement validation purposes.
+ A statement looks up and pre-loads all its stored functions
+ at prepare. Later on, if a function is gone from the cache,
+ execute may fail.
+ Remember the version of sp_head at prepare to be able to
+ invalidate the prepared statement at execute if it
+ changes.
+ */
+ ulong m_sp_cache_version;
+
+ const Sp_handler *m_handler;
+
+ int sp_cache_routine(THD *thd, bool lookup_only, sp_head **sp) const;
+};
+
+
+bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
+ const MDL_key *key,
+ const Sp_handler *handler,
+ TABLE_LIST *belong_to_view);
+void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx);
+bool sp_update_sp_used_routines(HASH *dst, HASH *src);
+void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
+ HASH *src, TABLE_LIST *belong_to_view);
+void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
+ SQL_I_List<Sroutine_hash_entry> *src,
+ TABLE_LIST *belong_to_view);
+
+extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
+ my_bool first);
+
+/*
+ Routines which allow open/lock and close mysql.proc table even when
+ we already have some tables open and locked.
+*/
+TABLE *open_proc_table_for_read(THD *thd);
+
+bool load_charset(MEM_ROOT *mem_root,
+ Field *field,
+ CHARSET_INFO *dflt_cs,
+ CHARSET_INFO **cs);
+
+bool load_collation(MEM_ROOT *mem_root,
+ Field *field,
+ CHARSET_INFO *dflt_cl,
+ CHARSET_INFO **cl);
+
+void sp_returns_type(THD *thd,
+ String &result,
+ const sp_head *sp);
+
+#endif /* _SP_H_ */