Commit 840d46b0 authored by Alexander Barkov's avatar Alexander Barkov

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().
parent 637af783
...@@ -1340,6 +1340,14 @@ class Item: public Value_source, ...@@ -1340,6 +1340,14 @@ class Item: public Value_source,
a constant expression. Used in the optimizer to propagate basic constants. a constant expression. Used in the optimizer to propagate basic constants.
*/ */
virtual bool basic_const_item() const { return 0; } 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) */ /* cloning of constant items (0 if it is not const) */
virtual Item *clone_item(THD *thd) { return 0; } virtual Item *clone_item(THD *thd) { return 0; }
virtual Item* build_clone(THD *thd) { return get_copy(thd); } virtual Item* build_clone(THD *thd) { return get_copy(thd); }
...@@ -2654,6 +2662,20 @@ class Item_splocal :public Item_sp_variable, ...@@ -2654,6 +2662,20 @@ class Item_splocal :public Item_sp_variable,
*/ */
Field *create_field_for_create_select(TABLE *table) Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(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 @@ class Item_param :public Item_basic_value, ...@@ -3606,6 +3628,13 @@ class Item_param :public Item_basic_value,
return item_type; 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() double val_real()
{ {
return can_return_value() ? value.val_real() : 0e0; return can_return_value() ? value.val_real() : 0e0;
...@@ -3808,6 +3837,7 @@ class Item_int :public Item_num ...@@ -3808,6 +3837,7 @@ class Item_int :public Item_num
String *val_str(String*); String *val_str(String*);
int save_in_field(Field *field, bool no_conversions); int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; } bool basic_const_item() const { return 1; }
bool is_order_clause_position() const { return true; }
Item *clone_item(THD *thd); Item *clone_item(THD *thd);
virtual void print(String *str, enum_query_type query_type); virtual void print(String *str, enum_query_type query_type);
Item *neg(THD *thd); Item *neg(THD *thd);
......
...@@ -68,6 +68,25 @@ int compare_decimal2(int* len, const char *s, const char *t) ...@@ -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 * Procedure *
proc_analyse_init(THD *thd, ORDER *param, select_result *result, proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list) List<Item> &field_list)
...@@ -88,17 +107,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, ...@@ -88,17 +107,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
else if (param->next) else if (param->next)
{ {
// first parameter // first parameter
if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) if (prepare_param(thd, param->item, proc_name, 0))
{
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);
goto err; goto err;
}
pc->max_tree_elements = (uint) (*param->item)->val_int(); pc->max_tree_elements = (uint) (*param->item)->val_int();
param = param->next; param = param->next;
if (param->next) // no third parameter possible if (param->next) // no third parameter possible
...@@ -107,25 +117,12 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, ...@@ -107,25 +117,12 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
goto err; goto err;
} }
// second parameter // second parameter
if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) if (prepare_param(thd, param->item, proc_name, 1))
{
DBUG_PRINT("info", ("fix_fields() for the second parameter failed"));
goto err; 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(); pc->max_treemem = (uint) (*param->item)->val_int();
} }
else if ((*param->item)->type() != Item::INT_ITEM || else if (prepare_param(thd, param->item, proc_name, 0))
(*param->item)->val_real() < 0)
{
my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
goto err; goto err;
}
// if only one parameter was given, it will be the value of max_tree_elements // if only one parameter was given, it will be the value of max_tree_elements
else else
{ {
......
...@@ -2887,8 +2887,7 @@ void st_select_lex::print_order(String *str, ...@@ -2887,8 +2887,7 @@ void st_select_lex::print_order(String *str,
else else
{ {
/* replace numeric reference with equivalent for ORDER constant */ /* replace numeric reference with equivalent for ORDER constant */
if (order->item[0]->type() == Item::INT_ITEM && if (order->item[0]->is_order_clause_position())
order->item[0]->basic_const_item())
{ {
/* make it expression instead of integer constant */ /* make it expression instead of integer constant */
str->append(STRING_WITH_LEN("''")); str->append(STRING_WITH_LEN("''"));
...@@ -6850,11 +6849,9 @@ Item *LEX::create_item_limit(THD *thd, ...@@ -6850,11 +6849,9 @@ Item *LEX::create_item_limit(THD *thd,
#endif #endif
safe_to_cache_query= 0; safe_to_cache_query= 0;
if (item->type() != Item::INT_ITEM) if (!item->is_valid_limit_clause_variable_with_error())
{
my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0));
return NULL; return NULL;
}
item->limit_clause_param= true; item->limit_clause_param= true;
return item; return item;
} }
...@@ -6877,11 +6874,8 @@ Item *LEX::create_item_limit(THD *thd, ...@@ -6877,11 +6874,8 @@ Item *LEX::create_item_limit(THD *thd,
Item_splocal *item; Item_splocal *item;
if (!(item= create_item_spvar_row_field(thd, rh, a, b, spv, start, end))) if (!(item= create_item_spvar_row_field(thd, rh, a, b, spv, start, end)))
return NULL; return NULL;
if (item->type() != Item::INT_ITEM) if (!item->is_valid_limit_clause_variable_with_error())
{
my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0));
return NULL; return NULL;
}
item->limit_clause_param= true; item->limit_clause_param= true;
return item; return item;
} }
......
...@@ -22771,12 +22771,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, ...@@ -22771,12 +22771,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array,
uint counter; uint counter;
enum_resolution_type resolution; enum_resolution_type resolution;
/* if (order_item->is_order_clause_position() && !from_window_spec)
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)
{ /* Order by position */ { /* Order by position */
uint count; uint count;
if (order->counter_used) if (order->counter_used)
......
...@@ -1031,6 +1031,14 @@ class Type_handler ...@@ -1031,6 +1031,14 @@ class Type_handler
{ {
return false; 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. Check whether a field type can be partially indexed by a key.
@param type field type @param type field type
...@@ -1906,6 +1914,8 @@ class Type_handler_int_result: public Type_handler_numeric ...@@ -1906,6 +1914,8 @@ class Type_handler_int_result: public Type_handler_numeric
public: public:
Item_result result_type() const { return INT_RESULT; } Item_result result_type() const { return INT_RESULT; }
Item_result cmp_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() {} virtual ~Type_handler_int_result() {}
const Type_handler *type_handler_for_comparison() const; const Type_handler *type_handler_for_comparison() const;
bool subquery_type_allows_materialization(const Item *inner, bool subquery_type_allows_materialization(const Item *inner,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment