mariadb/sql/sp_rcontext.h
unknown 6b2f13098a Patch for WL#2894: Make stored routine variables work
according to the standard.

The idea is to use Field-classes to implement stored routines
variables. Also, we should provide facade to Item-hierarchy
by Item_field class (it is necessary, since SRVs take part
in expressions).

The patch fixes the following bugs:
  - BUG#8702: Stored Procedures: No Error/Warning shown for inappropriate data 
    type matching; 
 
  - BUG#8768: Functions: For any unsigned data type, -ve values can be passed 
    and returned; 
 
  - BUG#8769: Functions: For Int datatypes, out of range values can be passed 
    and returned; 
 
  - BUG#9078: STORED PROCDURE: Decimal digits are not displayed when we use 
    DECIMAL datatype; 
 
  - BUG#9572: Stored procedures: variable type declarations ignored; 
 
  - BUG#12903: upper function does not work inside a function; 
 
  - BUG#13705: parameters to stored procedures are not verified; 
 
  - BUG#13808: ENUM type stored procedure parameter accepts non-enumerated
    data; 
 
  - BUG#13909: Varchar Stored Procedure Parameter always BINARY string (ignores 
    CHARACTER SET); 
 
  - BUG#14161: Stored procedure cannot retrieve bigint unsigned;

  - BUG#14188: BINARY variables have no 0x00 padding;

  - BUG#15148: Stored procedure variables accept non-scalar values;


mysql-test/r/ctype_ujis.result:
  Explicitly specify correct charset.
mysql-test/r/schema.result:
  Drop our test database to not affect this test if some test
  left it cause of failure.
mysql-test/r/show_check.result:
  Drop our test database to not affect this test if some test
  left it cause of failure.
mysql-test/r/skip_name_resolve.result:
  Ignore columns with unpredictable values.
mysql-test/r/sp-big.result:
  Add cleanup statement.
mysql-test/r/sp-dynamic.result:
  Add cleanup statements.
mysql-test/r/sp.result:
  Update result file.
mysql-test/r/sum_distinct-big.result:
  Update result file.
mysql-test/r/type_newdecimal-big.result:
  Update result file.
mysql-test/t/ctype_ujis.test:
  Explicitly specify correct charset.
mysql-test/t/schema.test:
  Drop our test database to not affect this test if some test
  left it cause of failure.
mysql-test/t/show_check.test:
  Drop our test database to not affect this test if some test
  left it cause of failure.
mysql-test/t/skip_name_resolve.test:
  Ignore columns with unpredictable values.
mysql-test/t/sp-big.test:
  Add cleanup statement.
mysql-test/t/sp-dynamic.test:
  Add cleanup statements.
mysql-test/t/sp.test:
  Non-scalar values prohibited for assignment to SP-vars;
  polishing.
mysql-test/t/type_newdecimal-big.test:
  Update type specification so that the variables
  can contain the large values used in the test.
sql/field.cc:
  Extract create_field::init() to initialize an existing
  instance of create_field from new_create_field().
sql/field.h:
  Extract create_field::init() to initialize an existing
  instance of create_field from new_create_field().
sql/item.cc:
  - Introduce a new class: Item_sp_variable -- a base class
    of stored-routine-variables classes;
  - Introduce Item_case_expr -- an Item, which is used to access
    to the expression of CASE statement;
sql/item.h:
  - Introduce a new class: Item_sp_variable -- a base class
    of stored-routine-variables classes;
  - Introduce Item_case_expr -- an Item, which is used to access
    to the expression of CASE statement;
sql/item_func.cc:
  Pass the Field (instead of Item) for the return value of
  a function to the function execution routine.
sql/item_func.h:
  Pass the Field (instead of Item) for the return value of
  a function to the function execution routine.
sql/mysql_priv.h:
  Move create_virtual_tmp_table() out of sql_select.h.
sql/sp.cc:
  Use create_result_field() instead of make_field().
sql/sp_head.cc:
  - Add a function to map enum_field_types to Item::Type;
  - Add sp_instr_push_case_expr instruction -- an instruction
    to push CASE expression into the active running context;
  - Add sp_instr_pop_case_expr instruction -- an instruction
    to pop CASE expression from the active running context;
  - Adapt the SP-execution code to using Fields instead of Items
    for SP-vars;
  - Use create_field structure for field description instead of
    a set of members.
sql/sp_head.h:
  - Add a function to map enum_field_types to Item::Type;
  - Add sp_instr_push_case_expr instruction -- an instruction
    to push CASE expression into the active running context;
  - Add sp_instr_pop_case_expr instruction -- an instruction
    to pop CASE expression from the active running context;
  - Adapt the SP-execution code to using Fields instead of Items
    for SP-vars;
  - Use create_field structure for field description instead of
    a set of members.
sql/sp_pcontext.cc:
  - Change rules to assign an index of SP-variable: use
    transparent index;
  - Add an operation to retrieve a list of defined SP-vars
    from the processing context recursively.
sql/sp_pcontext.h:
  - Change rules to assign an index of SP-variable: use
    transparent index;
  - Add an operation to retrieve a list of defined SP-vars
    from the processing context recursively.
sql/sp_rcontext.cc:
  - Change rules to assign an index of SP-variable: use
    transparent index;
  - Use a tmp virtual table to store SP-vars instead of Items;
  - Provide operations to work with CASE expresion.
sql/sp_rcontext.h:
  - Change rules to assign an index of SP-variable: use
    transparent index;
  - Use a tmp virtual table to store SP-vars instead of Items;
  - Provide operations to work with CASE expresion.
sql/sql_class.cc:
  - Reflect Item_splocal ctor changes;
  - Item_splocal::get_offset() has been renamed to get_var_idx().
sql/sql_class.h:
  Polishing.
sql/sql_parse.cc:
  Extract create_field::init() to initialize an existing
  instance of create_field from new_create_field().
sql/sql_select.cc:
  Take care of BLOB columns in create_virtual_tmp_table().
sql/sql_select.h:
  Move create_virtual_tmp_table() out of sql_select.h.
sql/sql_trigger.cc:
  Use boolean constants for boolean type instead of numerical ones.
sql/sql_yacc.yy:
  Provide an instance of create_field for each SP-var.
mysql-test/include/sp-vars.inc:
  The definitions of common-procedures, which are created
  under different circumstances.
mysql-test/r/sp-vars.result:
  Result file for the SP-vars test.
mysql-test/sp-vars.test:
  A new test for checking SP-vars functionality.
2005-12-07 17:01:17 +03:00

328 lines
7.4 KiB
C++

/* -*- C++ -*- */
/* Copyright (C) 2002 MySQL AB
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; either version 2 of the License, or
(at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _SP_RCONTEXT_H_
#define _SP_RCONTEXT_H_
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
struct sp_cond_type;
class sp_cursor;
struct sp_pvar;
class sp_lex_keeper;
class sp_instr_cpush;
#define SP_HANDLER_NONE 0
#define SP_HANDLER_EXIT 1
#define SP_HANDLER_CONTINUE 2
#define SP_HANDLER_UNDO 3
typedef struct
{
struct sp_cond_type *cond;
uint handler; // Location of handler
int type;
uint foffset; // Frame offset for the handlers declare level
} sp_handler_t;
/*
This class is a runtime context of a Stored Routine. It is used in an
execution and is intended to contain all dynamic objects (i.e. objects, which
can be changed during execution), such as:
- stored routine variables;
- cursors;
- handlers;
Runtime context is used with sp_head class. sp_head class is intended to
contain all static things, related to the stored routines (code, for example).
sp_head instance creates runtime context for the execution of a stored
routine.
There is a parsing context (an instance of sp_pcontext class), which is used
on parsing stage. However, now it contains some necessary for an execution
things, such as definition of used stored routine variables. That's why
runtime context needs a reference to the parsing context.
*/
class sp_rcontext : public Sql_alloc
{
sp_rcontext(const sp_rcontext &); /* Prevent use of these */
void operator=(sp_rcontext &);
public:
/*
Arena used to (re) allocate items on . E.g. reallocate INOUT/OUT
SP parameters when they don't fit into prealloced items. This
is common situation with String items. It is used mainly in
sp_eval_func_item().
*/
Query_arena *callers_arena;
#ifndef DBUG_OFF
/*
The routine for which this runtime context is created. Used for checking
if correct runtime context is used for variable handling.
*/
sp_head *sp;
#endif
sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld,
sp_rcontext *prev_runtime_ctx);
bool init(THD *thd);
~sp_rcontext();
int
set_variable(THD *thd, uint var_idx, Item *value);
Item *
get_item(uint var_idx);
Item **
get_item_addr(uint var_idx);
bool
set_return_value(THD *thd, Item *return_value_item);
inline bool
is_return_value_set() const
{
return m_return_value_set;
}
inline void
push_handler(struct sp_cond_type *cond, uint h, int type, uint f)
{
m_handler[m_hcount].cond= cond;
m_handler[m_hcount].handler= h;
m_handler[m_hcount].type= type;
m_handler[m_hcount].foffset= f;
m_hcount+= 1;
}
inline void
pop_handlers(uint count)
{
m_hcount-= count;
}
// Returns 1 if a handler was found, 0 otherwise.
bool
find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level);
// Returns handler type and sets *ip to location if one was found
inline int
found_handler(uint *ip, uint *fp)
{
if (m_hfound < 0)
return SP_HANDLER_NONE;
*ip= m_handler[m_hfound].handler;
*fp= m_handler[m_hfound].foffset;
return m_handler[m_hfound].type;
}
// Returns true if we found a handler in this context
inline bool
found_handler_here()
{
return (m_hfound >= 0);
}
// Clears the handler find state
inline void
clear_handler()
{
m_hfound= -1;
}
inline void
push_hstack(uint h)
{
m_hstack[m_hsp++]= h;
}
inline uint
pop_hstack()
{
return m_hstack[--m_hsp];
}
inline void
enter_handler(int hid)
{
m_in_handler[m_ihsp++]= hid;
}
inline void
exit_handler()
{
m_ihsp-= 1;
}
void
push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
void
pop_cursors(uint count);
void
pop_all_cursors()
{
pop_cursors(m_ccount);
}
inline sp_cursor *
get_cursor(uint i)
{
return m_cstack[i];
}
/*
CASE expressions support.
*/
int
set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item);
Item *
get_case_expr(int case_expr_id);
Item **
get_case_expr_addr(int case_expr_id);
private:
sp_pcontext *m_root_parsing_ctx;
/* Virtual table for storing variables. */
TABLE *m_var_table;
/*
Collection of Item_field proxies, each of them points to the corresponding
field in m_var_table.
*/
Item **m_var_items;
/*
This is a pointer to a field, which should contain return value for stored
functions (only). For stored procedures, this pointer is NULL.
*/
Field *m_return_value_fld;
/*
Indicates whether the return value (in m_return_value_fld) has been set
during execution.
*/
bool m_return_value_set;
sp_handler_t *m_handler; // Visible handlers
uint m_hcount; // Stack pointer for m_handler
uint *m_hstack; // Return stack for continue handlers
uint m_hsp; // Stack pointer for m_hstack
uint *m_in_handler; // Active handler, for recursion check
uint m_ihsp; // Stack pointer for m_in_handler
int m_hfound; // Set by find_handler; -1 if not found
sp_cursor **m_cstack;
uint m_ccount;
Item_cache **m_case_expr_holders;
/* Previous runtime context (NULL if none) */
sp_rcontext *m_prev_runtime_ctx;
private:
bool init_var_table(THD *thd);
bool init_var_items();
Item_cache *create_case_expr_holder(THD *thd, Item_result result_type);
int set_variable(THD *thd, Field *field, Item *value);
}; // class sp_rcontext : public Sql_alloc
/*
An interceptor of cursor result set used to implement
FETCH <cname> INTO <varlist>.
*/
class Select_fetch_into_spvars: public select_result_interceptor
{
List<struct sp_pvar> *spvar_list;
uint field_count;
public:
uint get_field_count() { return field_count; }
void set_spvar_list(List<struct sp_pvar> *vars) { spvar_list= vars; }
virtual bool send_eof() { return FALSE; }
virtual bool send_data(List<Item> &items);
virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
};
/* A mediator between stored procedures and server side cursors */
class sp_cursor : public Sql_alloc
{
public:
sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i);
virtual ~sp_cursor()
{
destroy();
}
sp_lex_keeper *
get_lex_keeper() { return m_lex_keeper; }
int
open(THD *thd);
int
close(THD *thd);
inline my_bool
is_open()
{
return test(server_side_cursor);
}
int
fetch(THD *, List<struct sp_pvar> *vars);
inline sp_instr_cpush *
get_instr()
{
return m_i;
}
private:
Select_fetch_into_spvars result;
sp_lex_keeper *m_lex_keeper;
Server_side_cursor *server_side_cursor;
sp_instr_cpush *m_i; // My push instruction
void
destroy();
}; // class sp_cursor : public Sql_alloc
#endif /* _SP_RCONTEXT_H_ */