1/* -*- C++ -*- */
2/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17#ifndef _SP_H_
18#define _SP_H_
19
20#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
21#include "sql_string.h" // LEX_STRING
22#include "sql_cmd.h"
23#include "mdl.h"
24
25class Field;
26class Open_tables_backup;
27class Open_tables_state;
28class Query_arena;
29class Query_tables_list;
30class Sroutine_hash_entry;
31class THD;
32class sp_cache;
33class sp_head;
34class sp_package;
35class sp_pcontext;
36class sp_name;
37class Database_qualified_name;
38struct st_sp_chistics;
39class Stored_program_creation_ctx;
40struct LEX;
41struct TABLE;
42struct TABLE_LIST;
43typedef struct st_hash HASH;
44template <typename T> class SQL_I_List;
45
46/*
47 Values for the type enum. This reflects the order of the enum declaration
48 in the CREATE TABLE command.
49*/
50enum stored_procedure_type
51{
52 TYPE_ENUM_FUNCTION=1,
53 TYPE_ENUM_PROCEDURE=2,
54 TYPE_ENUM_PACKAGE=3,
55 TYPE_ENUM_PACKAGE_BODY=4,
56 TYPE_ENUM_TRIGGER=5,
57 TYPE_ENUM_PROXY=6
58};
59
60
61class Sp_handler
62{
63 bool sp_resolve_package_routine_explicit(THD *thd,
64 sp_head *caller,
65 sp_name *name,
66 const Sp_handler **pkg_routine_hndlr,
67 Database_qualified_name *pkgname)
68 const;
69 bool sp_resolve_package_routine_implicit(THD *thd,
70 sp_head *caller,
71 sp_name *name,
72 const Sp_handler **pkg_routine_hndlr,
73 Database_qualified_name *pkgname)
74 const;
75protected:
76 int db_find_routine_aux(THD *thd, const Database_qualified_name *name,
77 TABLE *table) const;
78 int db_find_routine(THD *thd, const Database_qualified_name *name,
79 sp_head **sphp) const;
80 int db_find_and_cache_routine(THD *thd,
81 const Database_qualified_name *name,
82 sp_head **sp) const;
83 int db_load_routine(THD *thd, const Database_qualified_name *name,
84 sp_head **sphp,
85 sql_mode_t sql_mode,
86 const LEX_CSTRING &params,
87 const LEX_CSTRING &returns,
88 const LEX_CSTRING &body,
89 const st_sp_chistics &chistics,
90 const AUTHID &definer,
91 longlong created, longlong modified,
92 sp_package *parent,
93 Stored_program_creation_ctx *creation_ctx) const;
94 int sp_drop_routine_internal(THD *thd,
95 const Database_qualified_name *name,
96 TABLE *table) const;
97
98 sp_head *sp_clone_and_link_routine(THD *thd,
99 const Database_qualified_name *name,
100 sp_head *sp) const;
101 int sp_cache_package_routine(THD *thd,
102 const LEX_CSTRING &pkgname_cstr,
103 const Database_qualified_name *name,
104 bool lookup_only, sp_head **sp) const;
105 int sp_cache_package_routine(THD *thd,
106 const Database_qualified_name *name,
107 bool lookup_only, sp_head **sp) const;
108 sp_head *sp_find_package_routine(THD *thd,
109 const LEX_CSTRING pkgname_str,
110 const Database_qualified_name *name,
111 bool cache_only) const;
112 sp_head *sp_find_package_routine(THD *thd,
113 const Database_qualified_name *name,
114 bool cache_only) const;
115public: // TODO: make it private or protected
116 virtual int sp_find_and_drop_routine(THD *thd, TABLE *table,
117 const Database_qualified_name *name)
118 const;
119
120public:
121 virtual ~Sp_handler() {}
122 static const Sp_handler *handler(enum enum_sql_command cmd);
123 static const Sp_handler *handler(stored_procedure_type type);
124 static const Sp_handler *handler(MDL_key::enum_mdl_namespace ns);
125 /*
126 Return a handler only those SP objects that store
127 definitions in the mysql.proc system table
128 */
129 static const Sp_handler *handler_mysql_proc(stored_procedure_type type)
130 {
131 const Sp_handler *sph= handler(type);
132 return sph ? sph->sp_handler_mysql_proc() : NULL;
133 }
134
135 static bool eq_routine_name(const LEX_CSTRING &name1,
136 const LEX_CSTRING &name2)
137 {
138 return my_strnncoll(system_charset_info,
139 (const uchar *) name1.str, name1.length,
140 (const uchar *) name2.str, name2.length) == 0;
141 }
142 const char *type_str() const { return type_lex_cstring().str; }
143 virtual const char *show_create_routine_col1_caption() const
144 {
145 DBUG_ASSERT(0);
146 return "";
147 }
148 virtual const char *show_create_routine_col3_caption() const
149 {
150 DBUG_ASSERT(0);
151 return "";
152 }
153 virtual const Sp_handler *package_routine_handler() const
154 {
155 return this;
156 }
157 virtual stored_procedure_type type() const= 0;
158 virtual LEX_CSTRING type_lex_cstring() const= 0;
159 virtual LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
160 {
161 static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("???")};
162 DBUG_ASSERT(0);
163 return m_empty_body;
164 }
165 virtual MDL_key::enum_mdl_namespace get_mdl_type() const= 0;
166 virtual const Sp_handler *sp_handler_mysql_proc() const { return this; }
167 virtual sp_cache **get_cache(THD *) const { return NULL; }
168#ifndef NO_EMBEDDED_ACCESS_CHECKS
169 virtual HASH *get_priv_hash() const { return NULL; }
170#endif
171 virtual ulong recursion_depth(THD *thd) const { return 0; }
172 /**
173 Return appropriate error about recursion limit reaching
174
175 @param thd Thread handle
176 @param sp SP routine
177
178 @remark For functions and triggers we return error about
179 prohibited recursion. For stored procedures we
180 return about reaching recursion limit.
181 */
182 virtual void recursion_level_error(THD *thd, const sp_head *sp) const
183 {
184 my_error(ER_SP_NO_RECURSION, MYF(0));
185 }
186 virtual bool add_instr_freturn(THD *thd, sp_head *sp,
187 sp_pcontext *spcont,
188 Item *item, LEX *lex) const;
189 virtual bool add_instr_preturn(THD *thd, sp_head *sp,
190 sp_pcontext *spcont) const;
191
192 void add_used_routine(Query_tables_list *prelocking_ctx,
193 Query_arena *arena,
194 const Database_qualified_name *name) const;
195
196 bool sp_resolve_package_routine(THD *thd,
197 sp_head *caller,
198 sp_name *name,
199 const Sp_handler **pkg_routine_handler,
200 Database_qualified_name *pkgname) const;
201 virtual sp_head *sp_find_routine(THD *thd,
202 const Database_qualified_name *name,
203 bool cache_only) const;
204 virtual int sp_cache_routine(THD *thd, const Database_qualified_name *name,
205 bool lookup_only, sp_head **sp) const;
206
207 int sp_cache_routine_reentrant(THD *thd,
208 const Database_qualified_name *nm,
209 sp_head **sp) const;
210
211 bool sp_exist_routines(THD *thd, TABLE_LIST *procs) const;
212 bool sp_show_create_routine(THD *thd,
213 const Database_qualified_name *name) const;
214
215 bool sp_create_routine(THD *thd, const sp_head *sp) const;
216
217 int sp_update_routine(THD *thd, const Database_qualified_name *name,
218 const st_sp_chistics *chistics) const;
219
220 int sp_drop_routine(THD *thd, const Database_qualified_name *name) const;
221
222 sp_head *sp_load_for_information_schema(THD *thd, TABLE *proc_table,
223 const LEX_CSTRING &db,
224 const LEX_CSTRING &name,
225 const LEX_CSTRING &params,
226 const LEX_CSTRING &returns,
227 sql_mode_t sql_mode,
228 bool *free_sp_head) const;
229
230 /*
231 Make a SHOW CREATE statement.
232 @retval true on error
233 @retval false on success
234 */
235 virtual bool show_create_sp(THD *thd, String *buf,
236 const LEX_CSTRING &db,
237 const LEX_CSTRING &name,
238 const LEX_CSTRING &params,
239 const LEX_CSTRING &returns,
240 const LEX_CSTRING &body,
241 const st_sp_chistics &chistics,
242 const AUTHID &definer,
243 const DDL_options_st ddl_options,
244 sql_mode_t sql_mode) const;
245
246};
247
248
249class Sp_handler_procedure: public Sp_handler
250{
251public:
252 stored_procedure_type type() const { return TYPE_ENUM_PROCEDURE; }
253 LEX_CSTRING type_lex_cstring() const
254 {
255 static LEX_CSTRING m_type_str= { STRING_WITH_LEN("PROCEDURE")};
256 return m_type_str;
257 }
258 LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const;
259 const char *show_create_routine_col1_caption() const
260 {
261 return "Procedure";
262 }
263 const char *show_create_routine_col3_caption() const
264 {
265 return "Create Procedure";
266 }
267 MDL_key::enum_mdl_namespace get_mdl_type() const
268 {
269 return MDL_key::PROCEDURE;
270 }
271 const Sp_handler *package_routine_handler() const;
272 sp_cache **get_cache(THD *) const;
273#ifndef NO_EMBEDDED_ACCESS_CHECKS
274 HASH *get_priv_hash() const;
275#endif
276 ulong recursion_depth(THD *thd) const;
277 void recursion_level_error(THD *thd, const sp_head *sp) const;
278 bool add_instr_preturn(THD *thd, sp_head *sp, sp_pcontext *spcont) const;
279};
280
281
282class Sp_handler_package_procedure: public Sp_handler_procedure
283{
284public:
285 int sp_cache_routine(THD *thd, const Database_qualified_name *name,
286 bool lookup_only, sp_head **sp) const
287 {
288 return sp_cache_package_routine(thd, name, lookup_only, sp);
289 }
290 sp_head *sp_find_routine(THD *thd,
291 const Database_qualified_name *name,
292 bool cache_only) const
293 {
294 return sp_find_package_routine(thd, name, cache_only);
295 }
296};
297
298
299class Sp_handler_function: public Sp_handler
300{
301public:
302 stored_procedure_type type() const { return TYPE_ENUM_FUNCTION; }
303 LEX_CSTRING type_lex_cstring() const
304 {
305 static LEX_CSTRING m_type_str= { STRING_WITH_LEN("FUNCTION")};
306 return m_type_str;
307 }
308 LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const;
309 const char *show_create_routine_col1_caption() const
310 {
311 return "Function";
312 }
313 const char *show_create_routine_col3_caption() const
314 {
315 return "Create Function";
316 }
317 MDL_key::enum_mdl_namespace get_mdl_type() const
318 {
319 return MDL_key::FUNCTION;
320 }
321 const Sp_handler *package_routine_handler() const;
322 sp_cache **get_cache(THD *) const;
323#ifndef NO_EMBEDDED_ACCESS_CHECKS
324 HASH *get_priv_hash() const;
325#endif
326 bool add_instr_freturn(THD *thd, sp_head *sp, sp_pcontext *spcont,
327 Item *item, LEX *lex) const;
328};
329
330
331class Sp_handler_package_function: public Sp_handler_function
332{
333public:
334 int sp_cache_routine(THD *thd, const Database_qualified_name *name,
335 bool lookup_only, sp_head **sp) const
336 {
337 return sp_cache_package_routine(thd, name, lookup_only, sp);
338 }
339 sp_head *sp_find_routine(THD *thd,
340 const Database_qualified_name *name,
341 bool cache_only) const
342 {
343 return sp_find_package_routine(thd, name, cache_only);
344 }
345};
346
347
348class Sp_handler_package: public Sp_handler
349{
350public:
351 bool show_create_sp(THD *thd, String *buf,
352 const LEX_CSTRING &db,
353 const LEX_CSTRING &name,
354 const LEX_CSTRING &params,
355 const LEX_CSTRING &returns,
356 const LEX_CSTRING &body,
357 const st_sp_chistics &chistics,
358 const AUTHID &definer,
359 const DDL_options_st ddl_options,
360 sql_mode_t sql_mode) const;
361};
362
363
364class Sp_handler_package_spec: public Sp_handler_package
365{
366public: // TODO: make it private or protected
367 int sp_find_and_drop_routine(THD *thd, TABLE *table,
368 const Database_qualified_name *name)
369 const;
370public:
371 stored_procedure_type type() const { return TYPE_ENUM_PACKAGE; }
372 LEX_CSTRING type_lex_cstring() const
373 {
374 static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE")};
375 return m_type_str;
376 }
377 LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
378 {
379 static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("BEGIN END")};
380 return m_empty_body;
381 }
382 const char *show_create_routine_col1_caption() const
383 {
384 return "Package";
385 }
386 const char *show_create_routine_col3_caption() const
387 {
388 return "Create Package";
389 }
390 MDL_key::enum_mdl_namespace get_mdl_type() const
391 {
392 return MDL_key::PACKAGE_BODY;
393 }
394 sp_cache **get_cache(THD *) const;
395#ifndef NO_EMBEDDED_ACCESS_CHECKS
396 HASH *get_priv_hash() const;
397#endif
398};
399
400
401class Sp_handler_package_body: public Sp_handler_package
402{
403public:
404 stored_procedure_type type() const { return TYPE_ENUM_PACKAGE_BODY; }
405 LEX_CSTRING type_lex_cstring() const
406 {
407 static LEX_CSTRING m_type_str= {STRING_WITH_LEN("PACKAGE BODY")};
408 return m_type_str;
409 }
410 LEX_CSTRING empty_body_lex_cstring(sql_mode_t mode) const
411 {
412 static LEX_CSTRING m_empty_body= {STRING_WITH_LEN("BEGIN END")};
413 return m_empty_body;
414 }
415 const char *show_create_routine_col1_caption() const
416 {
417 return "Package body";
418 }
419 const char *show_create_routine_col3_caption() const
420 {
421 return "Create Package Body";
422 }
423 MDL_key::enum_mdl_namespace get_mdl_type() const
424 {
425 return MDL_key::PACKAGE_BODY;
426 }
427 sp_cache **get_cache(THD *) const;
428#ifndef NO_EMBEDDED_ACCESS_CHECKS
429 HASH *get_priv_hash() const;
430#endif
431};
432
433
434class Sp_handler_trigger: public Sp_handler
435{
436public:
437 stored_procedure_type type() const { return TYPE_ENUM_TRIGGER; }
438 LEX_CSTRING type_lex_cstring() const
439 {
440 static LEX_CSTRING m_type_str= { STRING_WITH_LEN("TRIGGER")};
441 return m_type_str;
442 }
443 MDL_key::enum_mdl_namespace get_mdl_type() const
444 {
445 DBUG_ASSERT(0);
446 return MDL_key::TRIGGER;
447 }
448 const Sp_handler *sp_handler_mysql_proc() const { return NULL; }
449};
450
451
452extern MYSQL_PLUGIN_IMPORT Sp_handler_function sp_handler_function;
453extern MYSQL_PLUGIN_IMPORT Sp_handler_procedure sp_handler_procedure;
454extern MYSQL_PLUGIN_IMPORT Sp_handler_package_spec sp_handler_package_spec;
455extern MYSQL_PLUGIN_IMPORT Sp_handler_package_body sp_handler_package_body;
456extern MYSQL_PLUGIN_IMPORT Sp_handler_package_function sp_handler_package_function;
457extern MYSQL_PLUGIN_IMPORT Sp_handler_package_procedure sp_handler_package_procedure;
458extern MYSQL_PLUGIN_IMPORT Sp_handler_trigger sp_handler_trigger;
459
460
461inline const Sp_handler *Sp_handler::handler(enum_sql_command cmd)
462{
463 switch (cmd) {
464 case SQLCOM_CREATE_PROCEDURE:
465 case SQLCOM_ALTER_PROCEDURE:
466 case SQLCOM_DROP_PROCEDURE:
467 case SQLCOM_SHOW_PROC_CODE:
468 case SQLCOM_SHOW_CREATE_PROC:
469 case SQLCOM_SHOW_STATUS_PROC:
470 return &sp_handler_procedure;
471 case SQLCOM_CREATE_SPFUNCTION:
472 case SQLCOM_ALTER_FUNCTION:
473 case SQLCOM_DROP_FUNCTION:
474 case SQLCOM_SHOW_FUNC_CODE:
475 case SQLCOM_SHOW_CREATE_FUNC:
476 case SQLCOM_SHOW_STATUS_FUNC:
477 return &sp_handler_function;
478 case SQLCOM_CREATE_PACKAGE:
479 case SQLCOM_DROP_PACKAGE:
480 case SQLCOM_SHOW_CREATE_PACKAGE:
481 case SQLCOM_SHOW_STATUS_PACKAGE:
482 return &sp_handler_package_spec;
483 case SQLCOM_CREATE_PACKAGE_BODY:
484 case SQLCOM_DROP_PACKAGE_BODY:
485 case SQLCOM_SHOW_CREATE_PACKAGE_BODY:
486 case SQLCOM_SHOW_STATUS_PACKAGE_BODY:
487 case SQLCOM_SHOW_PACKAGE_BODY_CODE:
488 return &sp_handler_package_body;
489 default:
490 break;
491 }
492 return NULL;
493}
494
495
496inline const Sp_handler *Sp_handler::handler(stored_procedure_type type)
497{
498 switch (type) {
499 case TYPE_ENUM_PROCEDURE:
500 return &sp_handler_procedure;
501 case TYPE_ENUM_FUNCTION:
502 return &sp_handler_function;
503 case TYPE_ENUM_PACKAGE:
504 return &sp_handler_package_spec;
505 case TYPE_ENUM_PACKAGE_BODY:
506 return &sp_handler_package_body;
507 case TYPE_ENUM_TRIGGER:
508 return &sp_handler_trigger;
509 case TYPE_ENUM_PROXY:
510 break;
511 }
512 return NULL;
513}
514
515
516inline const Sp_handler *Sp_handler::handler(MDL_key::enum_mdl_namespace type)
517{
518 switch (type) {
519 case MDL_key::FUNCTION:
520 return &sp_handler_function;
521 case MDL_key::PROCEDURE:
522 return &sp_handler_procedure;
523 case MDL_key::PACKAGE_BODY:
524 return &sp_handler_package_body;
525 case MDL_key::GLOBAL:
526 case MDL_key::SCHEMA:
527 case MDL_key::TABLE:
528 case MDL_key::TRIGGER:
529 case MDL_key::EVENT:
530 case MDL_key::COMMIT:
531 case MDL_key::USER_LOCK:
532 case MDL_key::NAMESPACE_END:
533 break;
534 }
535 return NULL;
536}
537
538
539/* Tells what SP_DEFAULT_ACCESS should be mapped to */
540#define SP_DEFAULT_ACCESS_MAPPING SP_CONTAINS_SQL
541
542// Return codes from sp_create_*, sp_drop_*, and sp_show_*:
543#define SP_OK 0
544#define SP_KEY_NOT_FOUND -1
545#define SP_OPEN_TABLE_FAILED -2
546#define SP_WRITE_ROW_FAILED -3
547#define SP_DELETE_ROW_FAILED -4
548#define SP_GET_FIELD_FAILED -5
549#define SP_PARSE_ERROR -6
550#define SP_INTERNAL_ERROR -7
551#define SP_NO_DB_ERROR -8
552#define SP_BAD_IDENTIFIER -9
553#define SP_BODY_TOO_LONG -10
554#define SP_FLD_STORE_FAILED -11
555
556/* DB storage of Stored PROCEDUREs and FUNCTIONs */
557enum
558{
559 MYSQL_PROC_FIELD_DB = 0,
560 MYSQL_PROC_FIELD_NAME,
561 MYSQL_PROC_MYSQL_TYPE,
562 MYSQL_PROC_FIELD_SPECIFIC_NAME,
563 MYSQL_PROC_FIELD_LANGUAGE,
564 MYSQL_PROC_FIELD_ACCESS,
565 MYSQL_PROC_FIELD_DETERMINISTIC,
566 MYSQL_PROC_FIELD_SECURITY_TYPE,
567 MYSQL_PROC_FIELD_PARAM_LIST,
568 MYSQL_PROC_FIELD_RETURNS,
569 MYSQL_PROC_FIELD_BODY,
570 MYSQL_PROC_FIELD_DEFINER,
571 MYSQL_PROC_FIELD_CREATED,
572 MYSQL_PROC_FIELD_MODIFIED,
573 MYSQL_PROC_FIELD_SQL_MODE,
574 MYSQL_PROC_FIELD_COMMENT,
575 MYSQL_PROC_FIELD_CHARACTER_SET_CLIENT,
576 MYSQL_PROC_FIELD_COLLATION_CONNECTION,
577 MYSQL_PROC_FIELD_DB_COLLATION,
578 MYSQL_PROC_FIELD_BODY_UTF8,
579 MYSQL_PROC_FIELD_AGGREGATE,
580 MYSQL_PROC_FIELD_COUNT
581};
582
583/* Drop all routines in database 'db' */
584int
585sp_drop_db_routines(THD *thd, const char *db);
586
587/**
588 Acquires exclusive metadata lock on all stored routines in the
589 given database.
590
591 @param thd Thread handler
592 @param db Database name
593
594 @retval false Success
595 @retval true Failure
596 */
597bool lock_db_routines(THD *thd, const char *db);
598
599/**
600 Structure that represents element in the set of stored routines
601 used by statement or routine.
602*/
603
604class Sroutine_hash_entry
605{
606public:
607 /**
608 Metadata lock request for routine.
609 MDL_key in this request is also used as a key for set.
610 */
611 MDL_request mdl_request;
612 /**
613 Next element in list linking all routines in set. See also comments
614 for LEX::sroutine/sroutine_list and sp_head::m_sroutines.
615 */
616 Sroutine_hash_entry *next;
617 /**
618 Uppermost view which directly or indirectly uses this routine.
619 0 if routine is not used in view. Note that it also can be 0 if
620 statement uses routine both via view and directly.
621 */
622 TABLE_LIST *belong_to_view;
623 /**
624 This is for prepared statement validation purposes.
625 A statement looks up and pre-loads all its stored functions
626 at prepare. Later on, if a function is gone from the cache,
627 execute may fail.
628 Remember the version of sp_head at prepare to be able to
629 invalidate the prepared statement at execute if it
630 changes.
631 */
632 ulong m_sp_cache_version;
633
634 const Sp_handler *m_handler;
635
636 int sp_cache_routine(THD *thd, bool lookup_only, sp_head **sp) const;
637};
638
639
640bool sp_add_used_routine(Query_tables_list *prelocking_ctx, Query_arena *arena,
641 const MDL_key *key,
642 const Sp_handler *handler,
643 TABLE_LIST *belong_to_view);
644void sp_remove_not_own_routines(Query_tables_list *prelocking_ctx);
645bool sp_update_sp_used_routines(HASH *dst, HASH *src);
646void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
647 HASH *src, TABLE_LIST *belong_to_view);
648void sp_update_stmt_used_routines(THD *thd, Query_tables_list *prelocking_ctx,
649 SQL_I_List<Sroutine_hash_entry> *src,
650 TABLE_LIST *belong_to_view);
651
652extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
653 my_bool first);
654
655/*
656 Routines which allow open/lock and close mysql.proc table even when
657 we already have some tables open and locked.
658*/
659TABLE *open_proc_table_for_read(THD *thd, Open_tables_backup *backup);
660
661bool load_charset(MEM_ROOT *mem_root,
662 Field *field,
663 CHARSET_INFO *dflt_cs,
664 CHARSET_INFO **cs);
665
666bool load_collation(MEM_ROOT *mem_root,
667 Field *field,
668 CHARSET_INFO *dflt_cl,
669 CHARSET_INFO **cl);
670
671void sp_returns_type(THD *thd,
672 String &result,
673 const sp_head *sp);
674
675#endif /* _SP_H_ */
676