diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-05-29 13:28:48 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-05-29 13:28:48 +0400 |
commit | 840d46b04f8269cc2a143bb8f25b78719a5123b9 (patch) | |
tree | d70d72ff0adaa70b0e1b694629f04e3480eadb43 | |
parent | 637af7838316a49267e55cde7cf96e23f63e5c9d (diff) | |
download | mariadb-git-840d46b04f8269cc2a143bb8f25b78719a5123b9.tar.gz |
MDEV-16316 Replace INT_ITEM references in the code behind ORDER, LIMIT, PROCEDURE clause
1. Adding new methods:
- Item::is_order_clause_position()
- Item_splocal::is_valid_limit_clause_variable_with_error()
- Type_handler::is_order_clause_position_type()
- is_limit_clause_valid_type()
and changing all tests related to the ORDER and LIMIT clauses
like "item->type()==INT_ITEM" to these new methods.
2. Adding a helper function prepare_param() in sql_analyse.cc
and replacing three pieces of duplicate code to prepare_param() calls.
Replacing the test "item->type()!=Item::INT_ITEM" to an equivalent
condition using item->basic_const_item() and type_handler()->result_type().
-rw-r--r-- | sql/item.h | 30 | ||||
-rw-r--r-- | sql/sql_analyse.cc | 47 | ||||
-rw-r--r-- | sql/sql_lex.cc | 14 | ||||
-rw-r--r-- | sql/sql_select.cc | 7 | ||||
-rw-r--r-- | sql/sql_type.h | 10 |
5 files changed, 67 insertions, 41 deletions
diff --git a/sql/item.h b/sql/item.h index cd6a993b869..d96541a9c0a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1340,6 +1340,14 @@ public: a constant expression. Used in the optimizer to propagate basic constants. */ virtual bool basic_const_item() const { return 0; } + /* + Test if "this" is an ORDER position (rather than an expression). + Notes: + - can be called before fix_fields(). + - local SP variables (even of integer types) are always expressions, not + positions. (And they can't be used before fix_fields is called for them). + */ + virtual bool is_order_clause_position() const { return false; } /* cloning of constant items (0 if it is not const) */ virtual Item *clone_item(THD *thd) { return 0; } virtual Item* build_clone(THD *thd) { return get_copy(thd); } @@ -2654,6 +2662,20 @@ public: */ Field *create_field_for_create_select(TABLE *table) { return tmp_table_field_from_field_type(table); } + + bool is_valid_limit_clause_variable_with_error() const + { + /* + In case if the variable has an anchored data type, e.g.: + DECLARE a TYPE OF t1.a; + type_handler() is set to &type_handler_null and this + function detects such variable as not valid in LIMIT. + */ + if (type_handler()->is_limit_clause_valid_type()) + return true; + my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); + return false; + } }; @@ -3606,6 +3628,13 @@ public: return item_type; } + bool is_order_clause_position() const + { + DBUG_ASSERT(fixed || state == NO_VALUE); + return state == SHORT_DATA_VALUE && + type_handler()->is_order_clause_position_type(); + } + double val_real() { return can_return_value() ? value.val_real() : 0e0; @@ -3808,6 +3837,7 @@ public: String *val_str(String*); int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } + bool is_order_clause_position() const { return true; } Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); Item *neg(THD *thd); diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 351ddb452d8..ce1c136fb44 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -68,6 +68,25 @@ int compare_decimal2(int* len, const char *s, const char *t) } +static bool +prepare_param(THD *thd, Item **item, const char *proc_name, uint pos) +{ + if (!(*item)->fixed && (*item)->fix_fields(thd, item)) + { + DBUG_PRINT("info", ("fix_fields() for the parameter %u failed", pos)); + return true; + } + if ((*item)->type_handler()->result_type() != INT_RESULT || + !(*item)->basic_const_item() || + (*item)->val_real() < 0) + { + my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); + return true; + } + return false; +} + + Procedure * proc_analyse_init(THD *thd, ORDER *param, select_result *result, List<Item> &field_list) @@ -88,17 +107,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, else if (param->next) { // first parameter - if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) - { - DBUG_PRINT("info", ("fix_fields() for the first parameter failed")); - goto err; - } - if ((*param->item)->type() != Item::INT_ITEM || - (*param->item)->val_real() < 0) - { - my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); + if (prepare_param(thd, param->item, proc_name, 0)) goto err; - } pc->max_tree_elements = (uint) (*param->item)->val_int(); param = param->next; if (param->next) // no third parameter possible @@ -107,25 +117,12 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, goto err; } // second parameter - if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) - { - DBUG_PRINT("info", ("fix_fields() for the second parameter failed")); + if (prepare_param(thd, param->item, proc_name, 1)) goto err; - } - if ((*param->item)->type() != Item::INT_ITEM || - (*param->item)->val_real() < 0) - { - my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); - goto err; - } pc->max_treemem = (uint) (*param->item)->val_int(); } - else if ((*param->item)->type() != Item::INT_ITEM || - (*param->item)->val_real() < 0) - { - my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name); + else if (prepare_param(thd, param->item, proc_name, 0)) goto err; - } // if only one parameter was given, it will be the value of max_tree_elements else { diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6f1d8b815fe..93810d2041c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2887,8 +2887,7 @@ void st_select_lex::print_order(String *str, else { /* replace numeric reference with equivalent for ORDER constant */ - if (order->item[0]->type() == Item::INT_ITEM && - order->item[0]->basic_const_item()) + if (order->item[0]->is_order_clause_position()) { /* make it expression instead of integer constant */ str->append(STRING_WITH_LEN("''")); @@ -6850,11 +6849,9 @@ Item *LEX::create_item_limit(THD *thd, #endif safe_to_cache_query= 0; - if (item->type() != Item::INT_ITEM) - { - my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); + if (!item->is_valid_limit_clause_variable_with_error()) return NULL; - } + item->limit_clause_param= true; return item; } @@ -6877,11 +6874,8 @@ Item *LEX::create_item_limit(THD *thd, Item_splocal *item; if (!(item= create_item_spvar_row_field(thd, rh, a, b, spv, start, end))) return NULL; - if (item->type() != Item::INT_ITEM) - { - my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); + if (!item->is_valid_limit_clause_variable_with_error()) return NULL; - } item->limit_clause_param= true; return item; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0eecb23a9c3..d676722e6e3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -22771,12 +22771,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, uint counter; enum_resolution_type resolution; - /* - Local SP variables may be int but are expressions, not positions. - (And they can't be used before fix_fields is called for them). - */ - if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item() && - !from_window_spec) + if (order_item->is_order_clause_position() && !from_window_spec) { /* Order by position */ uint count; if (order->counter_used) diff --git a/sql/sql_type.h b/sql/sql_type.h index dbd50dd77b5..74aacc0e0d1 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1031,6 +1031,14 @@ public: { return false; } + virtual bool is_order_clause_position_type() const + { + return false; + } + virtual bool is_limit_clause_valid_type() const + { + return false; + } /** Check whether a field type can be partially indexed by a key. @param type field type @@ -1906,6 +1914,8 @@ class Type_handler_int_result: public Type_handler_numeric public: Item_result result_type() const { return INT_RESULT; } Item_result cmp_type() const { return INT_RESULT; } + bool is_order_clause_position_type() const { return true; } + bool is_limit_clause_valid_type() const { return true; } virtual ~Type_handler_int_result() {} const Type_handler *type_handler_for_comparison() const; bool subquery_type_allows_materialization(const Item *inner, |