mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
Bug#49746: Const expression caching led to NDB not using engine condition
pushdown.
NDB supports only a limited set of item nodes for use in engine condition
pushdown. Because of this adding cache for const expression effectively
disabled this optimization.
The ndb_serialize_cond function is extended to support Item_cache and treat
it as a constant values.
A helper function called ndb_serialize_const is added. It is used to create
Ndb_cond value node from given const item.
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
##############################################################################
|
||||
|
||||
ndb_binlog_discover : Bug#54851 2010-07-02 alik ndb.ndb_binlog_discover crashes the server
|
||||
ndb_condition_pushdown : Bug#49746 2010-02-08 alik ndb_condition_pushdown fails in mysql-next-mr
|
||||
ndb_partition_error2 : Bug#40989 ndb_partition_error2 needs maintenance
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,110 @@
|
||||
typedef NdbDictionary::Column NDBCOL;
|
||||
typedef NdbDictionary::Table NDBTAB;
|
||||
|
||||
|
||||
/**
|
||||
Serialize a constant item into a Ndb_cond node.
|
||||
|
||||
@param const_type item's result type
|
||||
@param item item to be serialized
|
||||
@param curr_cond Ndb_cond node the item to be serialized into
|
||||
@param context Traverse context
|
||||
*/
|
||||
|
||||
static void ndb_serialize_const(Item_result const_type, const Item *item,
|
||||
Ndb_cond *curr_cond,
|
||||
Ndb_cond_traverse_context *context)
|
||||
{
|
||||
DBUG_ASSERT(item->const_item());
|
||||
switch (const_type) {
|
||||
case STRING_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::STRING_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(STRING_RESULT);
|
||||
context->expect_collation(item->collation.collation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
// Check that string result have correct collation
|
||||
if (!context->expecting_collation(item->collation.collation))
|
||||
{
|
||||
DBUG_PRINT("info", ("Found non-matching collation %s",
|
||||
item->collation.collation->name));
|
||||
context->supported= FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REAL_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::REAL_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(REAL_RESULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case INT_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::INT_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(INT_RESULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::DECIMAL_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(DECIMAL_RESULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Serialize the item tree into a linked list represented by Ndb_cond
|
||||
for fast generation of NbdScanFilter. Adds information such as
|
||||
@@ -113,7 +217,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
|
||||
to ndb_serialize_cond and end of rewrite statement
|
||||
is wrapped in end of ndb_serialize_cond
|
||||
*/
|
||||
if (context->expecting(item->type()))
|
||||
if (context->expecting(item->type()) || item->const_item())
|
||||
{
|
||||
// This is the <field>|<const> item, save it in the rewrite context
|
||||
rewrite_context2->left_hand_item= item;
|
||||
@@ -597,108 +701,12 @@ void ndb_serialize_cond(const Item *item, void *arg)
|
||||
DBUG_PRINT("info", ("result type %d", func_item->result_type()));
|
||||
if (func_item->const_item())
|
||||
{
|
||||
switch (func_item->result_type()) {
|
||||
case STRING_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::STRING_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(STRING_RESULT);
|
||||
context->expect_collation(func_item->collation.collation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
// Check that string result have correct collation
|
||||
if (!context->expecting_collation(item->collation.collation))
|
||||
{
|
||||
DBUG_PRINT("info", ("Found non-matching collation %s",
|
||||
item->collation.collation->name));
|
||||
context->supported= FALSE;
|
||||
}
|
||||
}
|
||||
// Skip any arguments since we will evaluate function instead
|
||||
DBUG_PRINT("info", ("Skip until end of arguments marker"));
|
||||
context->skip= func_item->argument_count();
|
||||
break;
|
||||
}
|
||||
case REAL_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::REAL_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(REAL_RESULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
}
|
||||
|
||||
// Skip any arguments since we will evaluate function instead
|
||||
DBUG_PRINT("info", ("Skip until end of arguments marker"));
|
||||
context->skip= func_item->argument_count();
|
||||
break;
|
||||
}
|
||||
case INT_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::INT_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(INT_RESULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
}
|
||||
|
||||
// Skip any arguments since we will evaluate function instead
|
||||
DBUG_PRINT("info", ("Skip until end of arguments marker"));
|
||||
context->skip= func_item->argument_count();
|
||||
break;
|
||||
}
|
||||
case DECIMAL_RESULT:
|
||||
{
|
||||
NDB_ITEM_QUALIFICATION q;
|
||||
q.value_type= Item::DECIMAL_ITEM;
|
||||
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
|
||||
if (! context->expecting_no_field_result())
|
||||
{
|
||||
// We have not seen the field argument yet
|
||||
context->expect_only(Item::FIELD_ITEM);
|
||||
context->expect_only_field_result(DECIMAL_RESULT);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expect another logical expression
|
||||
context->expect_only(Item::FUNC_ITEM);
|
||||
context->expect(Item::COND_ITEM);
|
||||
}
|
||||
// Skip any arguments since we will evaluate function instead
|
||||
DBUG_PRINT("info", ("Skip until end of arguments marker"));
|
||||
context->skip= func_item->argument_count();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ndb_serialize_const(func_item->result_type(), item, curr_cond,
|
||||
context);
|
||||
|
||||
// Skip any arguments since we will evaluate function instead
|
||||
DBUG_PRINT("info", ("Skip until end of arguments marker"));
|
||||
context->skip= func_item->argument_count();
|
||||
}
|
||||
else
|
||||
// Function does not return constant expression
|
||||
@@ -883,6 +891,19 @@ void ndb_serialize_cond(const Item *item, void *arg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Item::CACHE_ITEM:
|
||||
{
|
||||
DBUG_PRINT("info", ("CACHE_ITEM"));
|
||||
if (item->const_item())
|
||||
{
|
||||
ndb_serialize_const(((Item_cache*)item)->result_type(), item,
|
||||
curr_cond, context);
|
||||
}
|
||||
else
|
||||
context->supported= FALSE;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DBUG_PRINT("info", ("Found item of type %d", item->type()));
|
||||
|
||||
@@ -5931,7 +5931,8 @@ bool Item::cache_const_expr_analyzer(uchar **arg)
|
||||
a subselect (they use their own cache).
|
||||
*/
|
||||
if (const_item() &&
|
||||
!(item->basic_const_item() || item->type() == Item::FIELD_ITEM ||
|
||||
!(basic_const_item() || item->basic_const_item() ||
|
||||
item->type() == Item::FIELD_ITEM ||
|
||||
item->type() == SUBSELECT_ITEM ||
|
||||
/*
|
||||
Do not cache GET_USER_VAR() function as its const_item() may
|
||||
|
||||
10
sql/item.h
10
sql/item.h
@@ -3266,6 +3266,12 @@ public:
|
||||
bool basic_const_item() const
|
||||
{ return test(example && example->basic_const_item());}
|
||||
virtual void clear() { null_value= TRUE; value_cached= FALSE; }
|
||||
Item_result result_type() const
|
||||
{
|
||||
if (!example)
|
||||
return INT_RESULT;
|
||||
return Field::result_merge_type(example->field_type());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3335,7 +3341,9 @@ public:
|
||||
is_varbinary(item->type() == FIELD_ITEM &&
|
||||
cached_field_type == MYSQL_TYPE_VARCHAR &&
|
||||
!((const Item_field *) item)->field->has_charset())
|
||||
{}
|
||||
{
|
||||
collation.set(const_cast<DTCollation&>(item->collation));
|
||||
}
|
||||
double val_real();
|
||||
longlong val_int();
|
||||
String* val_str(String *);
|
||||
|
||||
Reference in New Issue
Block a user