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().
This commit is contained in:
parent
637af78383
commit
840d46b04f
30
sql/item.h
30
sql/item.h
@ -1340,6 +1340,14 @@ public:
|
|||||||
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 @@ public:
|
|||||||
*/
|
*/
|
||||||
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 @@ public:
|
|||||||
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 @@ public:
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
|||||||
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;
|
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_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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
#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,
|
|||||||
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,
|
|||||||
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 @@ public:
|
|||||||
{
|
{
|
||||||
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
|
|||||||
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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user