diff options
Diffstat (limited to 'sql/sp_pcontext.h')
-rw-r--r-- | sql/sp_pcontext.h | 333 |
1 files changed, 284 insertions, 49 deletions
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index d4d532340fb..9c879099410 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -41,7 +41,7 @@ public: }; /// Name of the SP-variable. - LEX_STRING name; + LEX_CSTRING name; /// Mode of the SP-variable. enum_mode mode; @@ -57,18 +57,35 @@ public: Item *default_value; /// Full type information (field meta-data) of the SP-variable. - Column_definition field_def; + Spvar_definition field_def; /// Field-type of the SP-variable. - enum_field_types sql_type() const { return field_def.sql_type; } + enum_field_types sql_type() const { return field_def.real_field_type(); } + + const Type_handler *type_handler() const { return field_def.type_handler(); } + public: - sp_variable(LEX_STRING _name, uint _offset) + sp_variable(const LEX_CSTRING *name_arg, uint offset_arg) :Sql_alloc(), - name(_name), + name(*name_arg), mode(MODE_IN), - offset(_offset), + offset(offset_arg), default_value(NULL) { } + /* + Find a ROW field by its qualified name. + @param var_name - the name of the variable + @param field_name - the name of the variable field + @param[OUT] row_field_offset - the index of the field + + @retval NULL if the variable with the given name was not found, + or it is not a row variable, or it does not have a field + with the given name, or a non-null pointer otherwise. + row_field_offset[0] is set only when the method returns !NULL. + */ + const Spvar_definition *find_row_field(const LEX_CSTRING *var_name, + const LEX_CSTRING *field_name, + uint *row_field_offset); }; /////////////////////////////////////////////////////////////////////////// @@ -80,6 +97,7 @@ public: /// 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: @@ -92,11 +110,14 @@ public: BEGIN, /// Label at iteration control - ITERATION + ITERATION, + + /// Label for jump + GOTO }; /// Name of the label. - LEX_STRING name; + LEX_CSTRING name; /// Instruction pointer of the label. uint ip; @@ -108,15 +129,17 @@ public: class sp_pcontext *ctx; public: - sp_label(LEX_STRING _name, uint _ip, enum_type _type, sp_pcontext *_ctx) + sp_label(const LEX_CSTRING *_name, + uint _ip, enum_type _type, sp_pcontext *_ctx) :Sql_alloc(), - name(_name), + name(*_name), ip(_ip), type(_type), ctx(_ctx) { } }; + /////////////////////////////////////////////////////////////////////////// /// This class represents condition-value term in DECLARE CONDITION or @@ -126,8 +149,9 @@ public: /// In some sense, this class is a union -- a set of filled attributes /// depends on the sp_condition_value::type value. -class sp_condition_value : public Sql_alloc +class sp_condition_value : public Sql_alloc, public Sql_state_errno { + bool m_is_user_defined; public: enum enum_type { @@ -141,29 +165,31 @@ public: /// Type of the condition value. enum_type type; - /// SQLSTATE of the condition value. - char sql_state[SQLSTATE_LENGTH+1]; - - /// MySQL error code of the condition value. - uint mysqlerr; - public: sp_condition_value(uint _mysqlerr) :Sql_alloc(), - type(ERROR_CODE), - mysqlerr(_mysqlerr) + Sql_state_errno(_mysqlerr), + m_is_user_defined(false), + type(ERROR_CODE) { } - sp_condition_value(const char *_sql_state) + sp_condition_value(uint _mysqlerr, const char *_sql_state) :Sql_alloc(), + Sql_state_errno(_mysqlerr, _sql_state), + m_is_user_defined(false), + type(ERROR_CODE) + { } + + sp_condition_value(const char *_sql_state, bool is_user_defined= false) + :Sql_alloc(), + Sql_state_errno(0, _sql_state), + m_is_user_defined(is_user_defined), type(SQLSTATE) - { - memcpy(sql_state, _sql_state, SQLSTATE_LENGTH); - sql_state[SQLSTATE_LENGTH]= 0; - } + { } sp_condition_value(enum_type _type) :Sql_alloc(), + m_is_user_defined(false), type(_type) { DBUG_ASSERT(type != ERROR_CODE && type != SQLSTATE); @@ -175,8 +201,39 @@ public: /// /// @return true if the instances are equal, false otherwise. bool equals(const sp_condition_value *cv) const; + + + /** + Checks if this condition is OK for search. + See also sp_context::find_handler(). + + @param identity - The condition identity + @param found_cv - A previously found matching condition or NULL. + @return true - If the current value matches identity and + makes a stronger match than the previously + found condition found_cv. + @return false - If the current value does not match identity, + of the current value makes a weaker match than found_cv. + */ + bool matches(const Sql_condition_identity &identity, + const sp_condition_value *found_cv) const; + + Sql_user_condition_identity get_user_condition_identity() const + { + return Sql_user_condition_identity(m_is_user_defined ? this : NULL); + } }; + +class sp_condition_value_user_defined: public sp_condition_value +{ +public: + sp_condition_value_user_defined() + :sp_condition_value("45000", true) + { } +}; + + /////////////////////////////////////////////////////////////////////////// /// This class represents 'DECLARE CONDITION' statement. @@ -186,19 +243,66 @@ class sp_condition : public Sql_alloc { public: /// Name of the condition. - LEX_STRING name; + LEX_CSTRING name; /// Value of the condition. sp_condition_value *value; public: - sp_condition(LEX_STRING _name, sp_condition_value *_value) + sp_condition(const LEX_CSTRING *name_arg, sp_condition_value *value_arg) :Sql_alloc(), - name(_name), - value(_value) + name(*name_arg), + value(value_arg) { } + sp_condition(const char *name_arg, size_t name_length_arg, + sp_condition_value *value_arg) + :value(value_arg) + { + name.str= name_arg; + name.length= name_length_arg; + } + bool eq_name(const LEX_CSTRING *str) const + { + return my_strnncoll(system_charset_info, + (const uchar *) name.str, name.length, + (const uchar *) str->str, str->length) == 0; + } }; + +/////////////////////////////////////////////////////////////////////////// + +/** + class sp_pcursor. + Stores information about a cursor: + - Cursor's name in LEX_STRING. + - Cursor's formal parameter descriptions. + + Formal parameter descriptions reside in a separate context block, + pointed by the "m_param_context" member. + + m_param_context can be NULL. This means a cursor with no parameters. + Otherwise, the number of variables in m_param_context means + the number of cursor's formal parameters. + + Note, m_param_context can be not NULL, but have no variables. + This is also means a cursor with no parameters (similar to NULL). +*/ +class sp_pcursor: public LEX_CSTRING +{ + class sp_pcontext *m_param_context; // Formal parameters + class sp_lex_cursor *m_lex; // The cursor statement LEX +public: + sp_pcursor(const LEX_CSTRING *name, class sp_pcontext *param_ctx, + class sp_lex_cursor *lex) + :LEX_CSTRING(*name), m_param_context(param_ctx), m_lex(lex) + { } + class sp_pcontext *param_context() const { return m_param_context; } + class sp_lex_cursor *lex() const { return m_lex; } + bool check_param_count_with_error(uint param_count) const; +}; + + /////////////////////////////////////////////////////////////////////////// /// This class represents 'DECLARE HANDLER' statement. @@ -267,6 +371,12 @@ public: HANDLER_SCOPE }; + class Lex_for_loop: public Lex_for_loop_st + { + public: + Lex_for_loop() { init(); } + }; + public: sp_pcontext(); ~sp_pcontext(); @@ -329,9 +439,22 @@ public: uint context_var_count() const { return (uint)m_vars.elements(); } - /// @return map index in this parsing context to runtime offset. - uint var_context2runtime(uint i) const - { return m_var_offset + i; } + /// return the i-th variable on the current context + sp_variable *get_context_variable(uint i) const + { + DBUG_ASSERT(i < m_vars.elements()); + return m_vars.at(i); + } + + /* + Return the i-th last context variable. + If i is 0, then return the very last variable in m_vars. + */ + sp_variable *get_last_context_variable(uint i= 0) const + { + DBUG_ASSERT(i < m_vars.elements()); + return m_vars.at(m_vars.elements() - i - 1); + } /// Add SP-variable to the parsing context. /// @@ -339,13 +462,13 @@ public: /// @param name Name of the SP-variable. /// /// @return instance of newly added SP-variable. - sp_variable *add_variable(THD *thd, LEX_STRING name); + sp_variable *add_variable(THD *thd, const LEX_CSTRING *name); /// 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<Column_definition> *field_def_lst) const; + void retrieve_field_definitions(List<Spvar_definition> *field_def_lst) const; /// Find SP-variable by name. /// @@ -358,7 +481,7 @@ public: /// @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; + sp_variable *find_variable(const LEX_CSTRING *name, bool current_scope_only) const; /// Find SP-variable by the offset in the root parsing context. /// @@ -401,9 +524,31 @@ public: // Labels. ///////////////////////////////////////////////////////////////////////// - sp_label *push_label(THD *thd, LEX_STRING name, uint ip); + sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip, + sp_label::enum_type type, List<sp_label> * list); + + sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip, + sp_label::enum_type type) + { return push_label(thd, name, ip, type, &m_labels); } - sp_label *find_label(LEX_STRING name); + sp_label *push_goto_label(THD *thd, const LEX_CSTRING *name, uint ip, + sp_label::enum_type type) + { return push_label(thd, name, ip, type, &m_goto_labels); } + + sp_label *push_label(THD *thd, const LEX_CSTRING *name, uint ip) + { return push_label(thd, name, ip, sp_label::IMPLICIT); } + + sp_label *push_goto_label(THD *thd, const LEX_CSTRING *name, uint ip) + { return push_goto_label(thd, name, ip, sp_label::GOTO); } + + sp_label *find_label(const LEX_CSTRING *name); + + sp_label *find_goto_label(const LEX_CSTRING *name, bool recusive); + + sp_label *find_goto_label(const LEX_CSTRING *name) + { return find_goto_label(name, true); } + + sp_label *find_label_current_loop_start(); sp_label *last_label() { @@ -415,19 +560,56 @@ public: return label; } + sp_label *last_goto_label() + { + return m_goto_labels.head(); + } + sp_label *pop_label() { return m_labels.pop(); } + bool block_label_declare(LEX_CSTRING *label) + { + sp_label *lab= find_label(label); + if (lab) + { + my_error(ER_SP_LABEL_REDEFINE, MYF(0), label->str); + return true; + } + return false; + } + ///////////////////////////////////////////////////////////////////////// // Conditions. ///////////////////////////////////////////////////////////////////////// - bool add_condition(THD *thd, LEX_STRING name, sp_condition_value *value); + bool add_condition(THD *thd, const LEX_CSTRING *name, + sp_condition_value *value); /// See comment for find_variable() above. - sp_condition_value *find_condition(LEX_STRING name, + sp_condition_value *find_condition(const LEX_CSTRING *name, bool current_scope_only) const; + sp_condition_value * + find_declared_or_predefined_condition(const LEX_CSTRING *name) const + { + sp_condition_value *p= find_condition(name, false); + if (p) + return p; + return find_predefined_condition(name); + } + + bool declare_condition(THD *thd, const LEX_CSTRING *name, + sp_condition_value *val) + { + if (find_condition(name, true)) + { + my_error(ER_SP_DUP_COND, MYF(0), name->str); + return true; + } + return add_condition(thd, name, val); + } + ///////////////////////////////////////////////////////////////////////// // Handlers. ///////////////////////////////////////////////////////////////////////// @@ -454,26 +636,46 @@ public: /// 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 value The error code and the SQL state /// @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; + sp_handler *find_handler(const Sql_condition_identity &identity) const; ///////////////////////////////////////////////////////////////////////// // Cursors. ///////////////////////////////////////////////////////////////////////// - bool add_cursor(LEX_STRING name); + bool add_cursor(const LEX_CSTRING *name, sp_pcontext *param_ctx, + class sp_lex_cursor *lex); /// See comment for find_variable() above. - bool find_cursor(LEX_STRING name, uint *poff, bool current_scope_only) const; + const sp_pcursor *find_cursor(const LEX_CSTRING *name, + uint *poff, bool current_scope_only) const; + + const sp_pcursor *find_cursor_with_error(const LEX_CSTRING *name, + uint *poff, + bool current_scope_only) const + { + const sp_pcursor *pcursor= find_cursor(name, poff, current_scope_only); + if (!pcursor) + { + my_error(ER_SP_CURSOR_MISMATCH, MYF(0), name->str); + return NULL; + } + return pcursor; + } + /// Find cursor by offset (for SHOW {PROCEDURE|FUNCTION} CODE only). + const sp_pcursor *find_cursor(uint offset) const; + + const sp_pcursor *get_cursor_by_local_frame_offset(uint offset) const + { return &m_cursors.at(offset); } + + uint cursor_offset() const + { return m_cursor_offset; } - /// Find cursor by offset (for debugging only). - const LEX_STRING *find_cursor(uint offset) const; + uint frame_cursor_count() const + { return m_cursors.elements(); } uint max_cursor_index() const { return m_max_cursor_index + (uint)m_cursors.elements(); } @@ -481,6 +683,15 @@ public: uint current_cursor_count() const { return m_cursor_offset + (uint)m_cursors.elements(); } + void set_for_loop(const Lex_for_loop_st &for_loop) + { + m_for_loop.init(for_loop); + } + const Lex_for_loop_st &for_loop() + { + return m_for_loop; + } + private: /// Constructor for a tree node. /// @param prev the parent parsing context @@ -493,6 +704,8 @@ private: sp_pcontext(const sp_pcontext &); void operator=(sp_pcontext &); + sp_condition_value *find_predefined_condition(const LEX_CSTRING *name) const; + private: /// m_max_var_index -- number of variables (including all types of arguments) /// in this context including all children contexts. @@ -538,19 +751,41 @@ private: Dynamic_array<sp_condition *> m_conditions; /// Stack of cursors. - Dynamic_array<LEX_STRING> m_cursors; + Dynamic_array<sp_pcursor> m_cursors; /// Stack of SQL-handlers. Dynamic_array<sp_handler *> m_handlers; - /// List of labels. + /* + In the below example the label <<lab>> has two meanings: + - GOTO lab : must go before the beginning of the loop + - CONTINUE lab : must go to the beginning of the loop + We solve this by storing block labels and goto labels into separate lists. + + BEGIN + <<lab>> + FOR i IN a..10 LOOP + ... + GOTO lab; + ... + CONTINUE lab; + ... + END LOOP; + END; + */ + /// List of block labels List<sp_label> m_labels; + /// List of goto labels + List<sp_label> m_goto_labels; /// Children contexts, used for destruction. Dynamic_array<sp_pcontext *> m_children; /// Scope of this parsing context. enum_scope m_scope; + + /// FOR LOOP characteristics + Lex_for_loop m_for_loop; }; // class sp_pcontext : public Sql_alloc |