Commit 48738f73 authored by Evgeny Potemkin's avatar Evgeny Potemkin

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.
parent 87f655d5
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
############################################################################## ##############################################################################
ndb_binlog_discover : Bug#54851 2010-07-02 alik ndb.ndb_binlog_discover crashes the server 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 ndb_partition_error2 : Bug#40989 ndb_partition_error2 needs maintenance
......
...@@ -35,6 +35,110 @@ ...@@ -35,6 +35,110 @@
typedef NdbDictionary::Column NDBCOL; typedef NdbDictionary::Column NDBCOL;
typedef NdbDictionary::Table NDBTAB; 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 Serialize the item tree into a linked list represented by Ndb_cond
for fast generation of NbdScanFilter. Adds information such as for fast generation of NbdScanFilter. Adds information such as
...@@ -113,7 +217,7 @@ void ndb_serialize_cond(const Item *item, void *arg) ...@@ -113,7 +217,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
to ndb_serialize_cond and end of rewrite statement to ndb_serialize_cond and end of rewrite statement
is wrapped in end of ndb_serialize_cond 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 // This is the <field>|<const> item, save it in the rewrite context
rewrite_context2->left_hand_item= item; rewrite_context2->left_hand_item= item;
...@@ -597,108 +701,12 @@ void ndb_serialize_cond(const Item *item, void *arg) ...@@ -597,108 +701,12 @@ void ndb_serialize_cond(const Item *item, void *arg)
DBUG_PRINT("info", ("result type %d", func_item->result_type())); DBUG_PRINT("info", ("result type %d", func_item->result_type()));
if (func_item->const_item()) if (func_item->const_item())
{ {
switch (func_item->result_type()) { ndb_serialize_const(func_item->result_type(), item, curr_cond,
case STRING_RESULT: context);
{
NDB_ITEM_QUALIFICATION q; // Skip any arguments since we will evaluate function instead
q.value_type= Item::STRING_ITEM; DBUG_PRINT("info", ("Skip until end of arguments marker"));
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); context->skip= func_item->argument_count();
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;
}
} }
else else
// Function does not return constant expression // Function does not return constant expression
...@@ -883,6 +891,19 @@ void ndb_serialize_cond(const Item *item, void *arg) ...@@ -883,6 +891,19 @@ void ndb_serialize_cond(const Item *item, void *arg)
} }
break; 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: default:
{ {
DBUG_PRINT("info", ("Found item of type %d", item->type())); DBUG_PRINT("info", ("Found item of type %d", item->type()));
......
...@@ -5931,7 +5931,8 @@ bool Item::cache_const_expr_analyzer(uchar **arg) ...@@ -5931,7 +5931,8 @@ bool Item::cache_const_expr_analyzer(uchar **arg)
a subselect (they use their own cache). a subselect (they use their own cache).
*/ */
if (const_item() && 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 || item->type() == SUBSELECT_ITEM ||
/* /*
Do not cache GET_USER_VAR() function as its const_item() may Do not cache GET_USER_VAR() function as its const_item() may
......
...@@ -3266,6 +3266,12 @@ public: ...@@ -3266,6 +3266,12 @@ public:
bool basic_const_item() const bool basic_const_item() const
{ return test(example && example->basic_const_item());} { return test(example && example->basic_const_item());}
virtual void clear() { null_value= TRUE; value_cached= FALSE; } 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: ...@@ -3335,7 +3341,9 @@ public:
is_varbinary(item->type() == FIELD_ITEM && is_varbinary(item->type() == FIELD_ITEM &&
cached_field_type == MYSQL_TYPE_VARCHAR && cached_field_type == MYSQL_TYPE_VARCHAR &&
!((const Item_field *) item)->field->has_charset()) !((const Item_field *) item)->field->has_charset())
{} {
collation.set(const_cast<DTCollation&>(item->collation));
}
double val_real(); double val_real();
longlong val_int(); longlong val_int();
String* val_str(String *); String* val_str(String *);
......
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