diff options
author | unknown <sanja@montyprogram.com> | 2013-06-19 14:32:14 +0300 |
---|---|---|
committer | unknown <sanja@montyprogram.com> | 2013-06-19 14:32:14 +0300 |
commit | dfcc502ab540b4d93fe3d40d0bac15fa3ae449dd (patch) | |
tree | ab179c039dab8cb251a20efcdd65f96a1eabf9a6 /sql/sp_pcontext.h | |
parent | 2534521f9a7d66b48cb9ca9402e82a0c58b156d8 (diff) | |
download | mariadb-git-dfcc502ab540b4d93fe3d40d0bac15fa3ae449dd.tar.gz |
Finished merging wl5986 started by Igor.
Diffstat (limited to 'sql/sp_pcontext.h')
-rw-r--r-- | sql/sp_pcontext.h | 813 |
1 files changed, 458 insertions, 355 deletions
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index f1d0d250c47..fbf32244665 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -24,438 +24,541 @@ #include "sql_string.h" // LEX_STRING #include "mysql_com.h" // enum_field_types #include "field.h" // Create_field +#include "sql_array.h" // Dynamic_array -class sp_pcontext; -typedef enum -{ - sp_param_in, - sp_param_out, - sp_param_inout -} sp_param_mode_t; +/// This class represents a stored program variable or a parameter +/// (also referenced as 'SP-variable'). -typedef struct sp_variable +class sp_variable : public Sql_alloc { - LEX_STRING name; - enum enum_field_types type; - sp_param_mode_t mode; - - /* - offset -- this the index to the variable's value in the runtime frame. - This is calculated during parsing and used when creating sp_instr_set - instructions and Item_splocal items. - I.e. values are set/referred by array indexing in runtime. - */ - uint offset; - - Item *dflt; - Create_field field_def; -} sp_variable_t; +public: + enum enum_mode + { + MODE_IN, + MODE_OUT, + MODE_INOUT + }; + /// Name of the SP-variable. + LEX_STRING name; -#define SP_LAB_IMPL 0 // Implicit label generated by parser -#define SP_LAB_BEGIN 1 // Label at BEGIN -#define SP_LAB_ITER 2 // Label at iteration control + /// Field-type of the SP-variable. + enum enum_field_types type; -/* - An SQL/PSM label. Can refer to the identifier used with the - "label_name:" construct which may precede some SQL/PSM statements, or - to an implicit implementation-dependent identifier which the parser - inserts before a high-level flow control statement such as - IF/WHILE/REPEAT/LOOP, when such statement is rewritten into - a combination of low-level jump/jump_if instructions and labels. -*/ + /// Mode of the SP-variable. + enum_mode mode; -typedef struct sp_label -{ - char *name; - uint ip; // Instruction index - int type; // begin/iter or ref/free - sp_pcontext *ctx; // The label's context -} sp_label_t; + /// The index to the variable's value in the runtime frame. + /// + /// It is calculated during parsing and used when creating sp_instr_set + /// instructions and Item_splocal items. I.e. values are set/referred by + /// array indexing in runtime. + uint offset; -typedef struct sp_cond_type -{ - enum { number, state, warning, notfound, exception } type; - char sqlstate[SQLSTATE_LENGTH+1]; - uint mysqlerr; -} sp_cond_type_t; + /// Default value of the SP-variable (if any). + Item *default_value; -/* - Sanity check for SQLSTATEs. Will not check if it's really an existing - state (there are just too many), but will check length bad characters. -*/ -extern bool -sp_cond_check(LEX_STRING *sqlstate); + /// Full type information (field meta-data) of the SP-variable. + Create_field field_def; -typedef struct sp_cond -{ - LEX_STRING name; - sp_cond_type_t *val; -} sp_cond_t; - -/** - The scope of a label in Stored Procedures, - for name resolution of labels in a parsing context. -*/ -enum label_scope_type -{ - /** - The labels declared in a parent context are in scope. - */ - LABEL_DEFAULT_SCOPE, - /** - The labels declared in a parent context are not in scope. - */ - LABEL_HANDLER_SCOPE +public: + sp_variable(LEX_STRING _name, enum_field_types _type, enum_mode _mode, + uint _offset) + :Sql_alloc(), + name(_name), + type(_type), + mode(_mode), + offset(_offset), + default_value(NULL) + { } }; -/** - The parse-time context, used to keep track of declared variables/parameters, - conditions, handlers, cursors and labels, during parsing. - sp_contexts are organized as a tree, with one object for each begin-end - block, one object for each exception handler, - plus a root-context for the parameters. - This is used during parsing for looking up defined names (e.g. declared - variables and visible labels), for error checking, and to calculate offsets - to be used at runtime. (During execution variable values, active handlers - and cursors, etc, are referred to by an index in a stack.) - Parsing contexts for exception handlers limit the visibility of labels. - The pcontext tree is also kept during execution and is used for error - checking (e.g. correct number of parameters), and in the future, used by - the debugger. -*/ +/////////////////////////////////////////////////////////////////////////// -class sp_pcontext : public Sql_alloc +/// This class represents an SQL/PSM label. Can refer to the identifier +/// used with the "label_name:" construct which may precede some SQL/PSM +/// statements, or to an implicit implementation-dependent identifier which +/// the parser inserts before a high-level flow control statement such as +/// IF/WHILE/REPEAT/LOOP, when such statement is rewritten into a +/// combination of low-level jump/jump_if instructions and labels. + +class sp_label : public Sql_alloc { public: - - /** - Constructor. - Builds a parsing context root node. - */ - sp_pcontext(); - - // Free memory - void - destroy(); - - /** - Create and push a new context in the tree. - @param label_scope label scope for the new parsing context - @return the node created - */ - sp_pcontext * - push_context(label_scope_type label_scope); - - /** - Pop a node from the parsing context tree. - @return the parent node - */ - sp_pcontext * - pop_context(); - - sp_pcontext * - parent_context() + enum enum_type { - return m_parent; - } + /// Implicit label generated by parser. + IMPLICIT, - /* - Number of handlers/cursors to pop between this context and 'ctx'. - If 'exclusive' is true, don't count the last block we are leaving; - this is used for LEAVE where we will jump to the cpop/hpop instructions. - */ - uint - diff_handlers(sp_pcontext *ctx, bool exclusive); - uint - diff_cursors(sp_pcontext *ctx, bool exclusive); - - - // - // Parameters and variables - // - - /* - The maximum number of variables used in this and all child contexts - In the root, this gives us the number of slots needed for variables - during execution. - */ - inline uint - max_var_index() - { - return m_max_var_index; - } + /// Label at BEGIN. + BEGIN, - /* - The current number of variables used in the parents (from the root), - including this context. - */ - inline uint - current_var_count() - { - return m_var_offset + m_vars.elements; - } + /// Label at iteration control + ITERATION + }; - /* The number of variables in this context alone */ - inline uint - context_var_count() - { - return m_vars.elements; - } + /// Name of the label. + LEX_STRING name; - /* Map index in this pcontext to runtime offset */ - inline uint - var_context2runtime(uint i) - { - return m_var_offset + i; - } + /// Instruction pointer of the label. + uint ip; - /* Set type of variable. 'i' is the offset from the top */ - inline void - set_type(uint i, enum enum_field_types type) - { - sp_variable_t *p= find_variable(i); + /// Type of the label. + enum_type type; - if (p) - p->type= type; - } + /// Scope of the label. + class sp_pcontext *ctx; - /* Set default value of variable. 'i' is the offset from the top */ - inline void - set_default(uint i, Item *it) - { - sp_variable_t *p= find_variable(i); +public: + sp_label(LEX_STRING _name, uint _ip, enum_type _type, sp_pcontext *_ctx) + :Sql_alloc(), + name(_name), + ip(_ip), + type(_type), + ctx(_ctx) + { } +}; - if (p) - p->dflt= it; - } +/////////////////////////////////////////////////////////////////////////// + +/// This class represents condition-value term in DECLARE CONDITION or +/// DECLARE HANDLER statements. sp_condition_value has little to do with +/// SQL-conditions. +/// +/// In some sense, this class is a union -- a set of filled attributes +/// depends on the sp_condition_value::type value. - sp_variable_t * - push_variable(LEX_STRING *name, enum enum_field_types type, - sp_param_mode_t mode); - - /* - Retrieve definitions of fields from the current context and its - children. - */ - void - retrieve_field_definitions(List<Create_field> *field_def_lst); - - // Find by name - sp_variable_t * - find_variable(LEX_STRING *name, my_bool scoped=0); - - // Find by offset (from the top) - sp_variable_t * - find_variable(uint offset); - - /* - Set the current scope boundary (for default values). - The argument is the number of variables to skip. - */ - inline void - declare_var_boundary(uint n) +class sp_condition_value : public Sql_alloc +{ +public: + enum enum_type { - m_pboundary= n; - } + ERROR_CODE, + SQLSTATE, + WARNING, + NOT_FOUND, + EXCEPTION + }; - /* - CASE expressions support. - */ + /// Type of the condition value. + enum_type type; - inline int - register_case_expr() - { - return m_num_case_exprs++; - } + /// SQLSTATE of the condition value. + char sql_state[SQLSTATE_LENGTH+1]; - inline int - get_num_case_exprs() const - { - return m_num_case_exprs; - } + /// MySQL error code of the condition value. + uint mysqlerr; - inline bool - push_case_expr_id(int case_expr_id) +public: + sp_condition_value(uint _mysqlerr) + :Sql_alloc(), + type(ERROR_CODE), + mysqlerr(_mysqlerr) + { } + + sp_condition_value(const char *_sql_state) + :Sql_alloc(), + type(SQLSTATE) { - return insert_dynamic(&m_case_expr_id_lst, (uchar*) &case_expr_id); + memcpy(sql_state, _sql_state, SQLSTATE_LENGTH); + sql_state[SQLSTATE_LENGTH]= 0; } - inline void - pop_case_expr_id() + sp_condition_value(enum_type _type) + :Sql_alloc(), + type(_type) { - pop_dynamic(&m_case_expr_id_lst); + DBUG_ASSERT(type != ERROR_CODE && type != SQLSTATE); } - inline int - get_current_case_expr_id() const - { - int case_expr_id; + /// Check if two instances of sp_condition_value are equal or not. + /// + /// @param cv another instance of sp_condition_value to check. + /// + /// @return true if the instances are equal, false otherwise. + bool equals(const sp_condition_value *cv) const; +}; - get_dynamic((DYNAMIC_ARRAY*)&m_case_expr_id_lst, (uchar*) &case_expr_id, - m_case_expr_id_lst.elements - 1); +/////////////////////////////////////////////////////////////////////////// - return case_expr_id; - } +/// This class represents 'DECLARE CONDITION' statement. +/// sp_condition has little to do with SQL-conditions. - // - // Labels - // +class sp_condition : public Sql_alloc +{ +public: + /// Name of the condition. + LEX_STRING name; - sp_label_t * - push_label(char *name, uint ip); + /// Value of the condition. + sp_condition_value *value; - sp_label_t * - find_label(char *name); +public: + sp_condition(LEX_STRING _name, sp_condition_value *_value) + :Sql_alloc(), + name(_name), + value(_value) + { } +}; - inline sp_label_t * - last_label() - { - sp_label_t *lab= m_label.head(); +/////////////////////////////////////////////////////////////////////////// - if (!lab && m_parent) - lab= m_parent->last_label(); - return lab; - } +/// This class represents 'DECLARE HANDLER' statement. - inline sp_label_t * - pop_label() +class sp_handler : public Sql_alloc +{ +public: + /// Enumeration of possible handler types. + /// Note: UNDO handlers are not (and have never been) supported. + enum enum_type { - return m_label.pop(); - } + EXIT, + CONTINUE + }; - // - // Conditions - // + /// Handler type. + enum_type type; - int - push_cond(LEX_STRING *name, sp_cond_type_t *val); + /// Conditions caught by this handler. + List<sp_condition_value> condition_values; - sp_cond_type_t * - find_cond(LEX_STRING *name, my_bool scoped=0); +public: + /// The constructor. + /// + /// @param _type SQL-handler type. + sp_handler(enum_type _type) + :Sql_alloc(), + type(_type) + { } +}; - // - // Handlers - // +/////////////////////////////////////////////////////////////////////////// + +/// The class represents parse-time context, which keeps track of declared +/// variables/parameters, conditions, handlers, cursors and labels. +/// +/// sp_context objects are organized in a tree according to the following +/// rules: +/// - one sp_pcontext object corresponds for for each BEGIN..END block; +/// - one sp_pcontext object corresponds for each exception handler; +/// - one additional sp_pcontext object is created to contain +/// Stored Program parameters. +/// +/// sp_pcontext objects are used both at parse-time and at runtime. +/// +/// During the parsing stage sp_pcontext objects are used: +/// - to look up defined names (e.g. declared variables and visible +/// labels); +/// - to check for duplicates; +/// - for error checking; +/// - to calculate offsets to be used at runtime. +/// +/// During the runtime phase, a tree of sp_pcontext objects is used: +/// - for error checking (e.g. to check correct number of parameters); +/// - to resolve SQL-handlers. - inline void - push_handler(sp_cond_type_t *cond) +class sp_pcontext : public Sql_alloc +{ +public: + enum enum_scope { - insert_dynamic(&m_handlers, (uchar*)&cond); - } - - bool - find_handler(sp_cond_type *cond); + /// REGULAR_SCOPE designates regular BEGIN ... END blocks. + REGULAR_SCOPE, - inline uint - max_handler_index() - { - return m_max_handler_index + m_context_handlers; - } + /// HANDLER_SCOPE designates SQL-handler blocks. + HANDLER_SCOPE + }; - inline void - add_handlers(uint n) +public: + sp_pcontext(); + ~sp_pcontext(); + + + /// Create and push a new context in the tree. + + /// @param thd thread context. + /// @param scope scope of the new parsing context. + /// @return the node created. + sp_pcontext *push_context(THD *thd, enum_scope scope); + + /// Pop a node from the parsing context tree. + /// @return the parent node. + sp_pcontext *pop_context(); + + sp_pcontext *parent_context() const + { return m_parent; } + + /// Calculate and return the number of handlers to pop between the given + /// context and this one. + /// + /// @param ctx the other parsing context. + /// @param exclusive specifies if the last scope should be excluded. + /// + /// @return the number of handlers to pop between the given context and + /// this one. If 'exclusive' is true, don't count the last scope we are + /// leaving; this is used for LEAVE where we will jump to the hpop + /// instructions. + uint diff_handlers(const sp_pcontext *ctx, bool exclusive) const; + + /// Calculate and return the number of cursors to pop between the given + /// context and this one. + /// + /// @param ctx the other parsing context. + /// @param exclusive specifies if the last scope should be excluded. + /// + /// @return the number of cursors to pop between the given context and + /// this one. If 'exclusive' is true, don't count the last scope we are + /// leaving; this is used for LEAVE where we will jump to the cpop + /// instructions. + uint diff_cursors(const sp_pcontext *ctx, bool exclusive) const; + + ///////////////////////////////////////////////////////////////////////// + // SP-variables (parameters and variables). + ///////////////////////////////////////////////////////////////////////// + + /// @return the maximum number of variables used in this and all child + /// contexts. For the root parsing context, this gives us the number of + /// slots needed for variables during the runtime phase. + uint max_var_index() const + { return m_max_var_index; } + + /// @return the current number of variables used in the parent contexts + /// (from the root), including this context. + uint current_var_count() const + { return m_var_offset + m_vars.elements(); } + + /// @return the number of variables in this context alone. + uint context_var_count() const + { return m_vars.elements(); } + + /// @return map index in this parsing context to runtime offset. + uint var_context2runtime(uint i) const + { return m_var_offset + i; } + + /// Add SP-variable to the parsing context. + /// + /// @param thd Thread context. + /// @param name Name of the SP-variable. + /// @param type Type of the SP-variable. + /// @param mode Mode of the SP-variable. + /// + /// @return instance of newly added SP-variable. + sp_variable *add_variable(THD *thd, + LEX_STRING name, + enum enum_field_types type, + sp_variable::enum_mode mode); + + /// Retrieve full type information about SP-variables in this parsing + /// context and its children. + /// + /// @param field_def_lst[out] Container to store type information. + void retrieve_field_definitions(List<Create_field> *field_def_lst) const; + + /// Find SP-variable by name. + /// + /// The function does a linear search (from newer to older variables, + /// in case we have shadowed names). + /// + /// The function is called only at parsing time. + /// + /// @param name Variable name. + /// @param current_scope_only A flag if we search only in current scope. + /// + /// @return instance of found SP-variable, or NULL if not found. + sp_variable *find_variable(LEX_STRING name, bool current_scope_only) const; + + /// Find SP-variable by the offset in the root parsing context. + /// + /// The function is used for two things: + /// - When evaluating parameters at the beginning, and setting out parameters + /// at the end, of invocation. (Top frame only, so no recursion then.) + /// - For printing of sp_instr_set. (Debug mode only.) + /// + /// @param offset Variable offset in the root parsing context. + /// + /// @return instance of found SP-variable, or NULL if not found. + sp_variable *find_variable(uint offset) const; + + /// Set the current scope boundary (for default values). + /// + /// @param n The number of variables to skip. + void declare_var_boundary(uint n) + { m_pboundary= n; } + + ///////////////////////////////////////////////////////////////////////// + // CASE expressions. + ///////////////////////////////////////////////////////////////////////// + + int register_case_expr() + { return m_num_case_exprs++; } + + int get_num_case_exprs() const + { return m_num_case_exprs; } + + bool push_case_expr_id(int case_expr_id) + { return m_case_expr_ids.append(case_expr_id); } + + void pop_case_expr_id() + { m_case_expr_ids.pop(); } + + int get_current_case_expr_id() const + { return *m_case_expr_ids.back(); } + + ///////////////////////////////////////////////////////////////////////// + // Labels. + ///////////////////////////////////////////////////////////////////////// + + sp_label *push_label(THD *thd, LEX_STRING name, uint ip); + + sp_label *find_label(LEX_STRING name); + + sp_label *last_label() { - m_context_handlers+= n; - } - - // - // Cursors - // + sp_label *label= m_labels.head(); - int - push_cursor(LEX_STRING *name); + if (!label && m_parent) + label= m_parent->last_label(); - my_bool - find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0); - - /* Find by offset (for debugging only) */ - my_bool - find_cursor(uint offset, LEX_STRING *n); - - inline uint - max_cursor_index() - { - return m_max_cursor_index + m_cursors.elements; - } - - inline uint - current_cursor_count() - { - return m_cursor_offset + m_cursors.elements; + return label; } -protected: + sp_label *pop_label() + { return m_labels.pop(); } + + ///////////////////////////////////////////////////////////////////////// + // Conditions. + ///////////////////////////////////////////////////////////////////////// + + bool add_condition(THD *thd, LEX_STRING name, sp_condition_value *value); + + /// See comment for find_variable() above. + sp_condition_value *find_condition(LEX_STRING name, + bool current_scope_only) const; + + ///////////////////////////////////////////////////////////////////////// + // Handlers. + ///////////////////////////////////////////////////////////////////////// + + sp_handler *add_handler(THD* thd, sp_handler::enum_type type); + + /// This is an auxilary parsing-time function to check if an SQL-handler + /// exists in the current parsing context (current scope) for the given + /// SQL-condition. This function is used to check for duplicates during + /// the parsing phase. + /// + /// This function can not be used during the runtime phase to check + /// SQL-handler existence because it searches for the SQL-handler in the + /// current scope only (during runtime, current and parent scopes + /// should be checked according to the SQL-handler resolution rules). + /// + /// @param condition_value the handler condition value + /// (not SQL-condition!). + /// + /// @retval true if such SQL-handler exists. + /// @retval false otherwise. + bool check_duplicate_handler(const sp_condition_value *cond_value) const; + + /// Find an SQL handler for the given SQL condition according to the + /// SQL-handler resolution rules. This function is used at runtime. + /// + /// @param sql_state The SQL condition state + /// @param sql_errno The error code + /// @param level The SQL condition level + /// + /// @return a pointer to the found SQL-handler or NULL. + sp_handler *find_handler(const char *sql_state, + uint sql_errno, + Sql_condition::enum_warning_level level) const; + + ///////////////////////////////////////////////////////////////////////// + // Cursors. + ///////////////////////////////////////////////////////////////////////// + + bool add_cursor(LEX_STRING name); + + /// See comment for find_variable() above. + bool find_cursor(LEX_STRING name, uint *poff, bool current_scope_only) const; + + /// Find cursor by offset (for debugging only). + const LEX_STRING *find_cursor(uint offset) const; + + uint max_cursor_index() const + { return m_max_cursor_index + m_cursors.elements(); } + + uint current_cursor_count() const + { return m_cursor_offset + m_cursors.elements(); } - /** - Constructor for a tree node. - @param prev the parent parsing context - @param label_scope label_scope for this parsing context - */ - sp_pcontext(sp_pcontext *prev, label_scope_type label_scope); - - /* - m_max_var_index -- number of variables (including all types of arguments) - in this context including all children contexts. - - m_max_var_index >= m_vars.elements. +private: + /// Constructor for a tree node. + /// @param prev the parent parsing context + /// @param scope scope of this parsing context + sp_pcontext(sp_pcontext *prev, enum_scope scope); - m_max_var_index of the root parsing context contains number of all - variables (including arguments) in all enclosed contexts. - */ - uint m_max_var_index; + void init(uint var_offset, uint cursor_offset, int num_case_expressions); - // The maximum sub context's framesizes - uint m_max_cursor_index; - uint m_max_handler_index; - uint m_context_handlers; // No. of handlers in this context + /* Prevent use of these */ + sp_pcontext(const sp_pcontext &); + void operator=(sp_pcontext &); private: + /// m_max_var_index -- number of variables (including all types of arguments) + /// in this context including all children contexts. + /// + /// m_max_var_index >= m_vars.elements(). + /// + /// m_max_var_index of the root parsing context contains number of all + /// variables (including arguments) in all enclosed contexts. + uint m_max_var_index; + + /// The maximum sub context's framesizes. + uint m_max_cursor_index; - sp_pcontext *m_parent; // Parent context - - /* - m_var_offset -- this is an index of the first variable in this - parsing context. - - m_var_offset is 0 for root context. + /// Parent context. + sp_pcontext *m_parent; - Since now each variable is stored in separate place, no reuse is done, - so m_var_offset is different for all enclosed contexts. - */ + /// An index of the first SP-variable in this parsing context. The index + /// belongs to a runtime table of SP-variables. + /// + /// Note: + /// - m_var_offset is 0 for root parsing context; + /// - m_var_offset is different for all nested parsing contexts. uint m_var_offset; - uint m_cursor_offset; // Cursor offset for this context + /// Cursor offset for this context. + uint m_cursor_offset; - /* - Boundary for finding variables in this context. This is the number - of variables currently "invisible" to default clauses. - This is normally 0, but will be larger during parsing of - DECLARE ... DEFAULT, to get the scope right for DEFAULT values. - */ + /// Boundary for finding variables in this context. This is the number of + /// variables currently "invisible" to default clauses. This is normally 0, + /// but will be larger during parsing of DECLARE ... DEFAULT, to get the + /// scope right for DEFAULT values. uint m_pboundary; int m_num_case_exprs; - DYNAMIC_ARRAY m_vars; // Parameters/variables - DYNAMIC_ARRAY m_case_expr_id_lst; /* Stack of CASE expression ids. */ - DYNAMIC_ARRAY m_conds; // Conditions - DYNAMIC_ARRAY m_cursors; // Cursors - DYNAMIC_ARRAY m_handlers; // Handlers, for checking for duplicates + /// SP parameters/variables. + Dynamic_array<sp_variable *> m_vars; - List<sp_label_t> m_label; // The label list + /// Stack of CASE expression ids. + Dynamic_array<int> m_case_expr_ids; - List<sp_pcontext> m_children; // Children contexts, used for destruction + /// Stack of SQL-conditions. + Dynamic_array<sp_condition *> m_conditions; - /** - Scope of labels for this parsing context. - */ - label_scope_type m_label_scope; + /// Stack of cursors. + Dynamic_array<LEX_STRING> m_cursors; -private: - sp_pcontext(const sp_pcontext &); /* Prevent use of these */ - void operator=(sp_pcontext &); + /// Stack of SQL-handlers. + Dynamic_array<sp_handler *> m_handlers; + + /// List of labels. + List<sp_label> m_labels; + + /// Children contexts, used for destruction. + Dynamic_array<sp_pcontext *> m_children; + + /// Scope of this parsing context. + enum_scope m_scope; }; // class sp_pcontext : public Sql_alloc |