Commit 9968b41d authored by unknown's avatar unknown

Fixes for condition pushdown to storage engine based on comments from code review


mysql-test/r/ndb_condition_pushdown.result:
  Added more tests  for condition pushdown to storage engine based on comments from code review
mysql-test/t/ndb_condition_pushdown.test:
  Added more tests  for condition pushdown to storage engine based on comments from code review
parent a2bb52c7
DROP TABLE IF EXISTS t1,t2;
CREATE TABLE t1 (
auto int(5) unsigned NOT NULL auto_increment,
string char(10) default "hello",
vstring varchar(10) default "hello",
bin binary(7) default "hello",
vbin varbinary(7) default "hello",
string char(10),
vstring varchar(10),
bin binary(7),
vbin varbinary(7),
tiny tinyint(4) DEFAULT '0' NOT NULL ,
short smallint(6) DEFAULT '1' NOT NULL ,
medium mediumint(8) DEFAULT '0' NOT NULL,
......@@ -233,17 +233,41 @@ auto
2
3
4
select auto from t1 where
string like "b%" and
vstring like "b%" and
bin like "b%" and
vbin like "b%"
order by auto;
auto
2
select auto from t1 where
string not like "b%" and
vstring not like "b%" and
bin not like "b%" and
vbin not like "b%"
order by auto;
auto
1
3
4
select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
pk1 attr1 attr2 attr3
2 2 NULL NULL
3 3 3 d
select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
pk1 attr1 attr2 attr3
3 3 3 d
4 4 4 e
5 5 5 f
select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
pk1 attr1 attr2 attr3 attr4
2 2 9223372036854775804 2 c
4 4 9223372036854775806 4 e
5 5 9223372036854775807 5 f
select * from t2,t3 where t2.attr1 > 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
pk1 attr1 attr2 attr3 pk1 attr1 attr2 attr3 attr4
0 0 0 a 0 0 0 0 a
select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
pk1 attr1 attr2 attr3 attr4
2 2 9223372036854775804 2 c
......@@ -257,8 +281,8 @@ set engine_condition_pushdown = on;
select auto from t1 where
string = "aaaa" and
vstring = "aaaa" and
bin = "aaaa" and
vbin = "aaaa" and
/* bin = "aaaa" and
vbin = "aaaa" and */
tiny = -1 and
short = -1 and
medium = -1 and
......@@ -285,8 +309,8 @@ auto
select auto from t1 where
string != "aaaa" and
vstring != "aaaa" and
bin != "aaaa" and
vbin != "aaaa" and
/* bin != "aaaa" and
vbin != "aaaa" and */
tiny != -1 and
short != -1 and
medium != -1 and
......@@ -315,8 +339,8 @@ auto
select auto from t1 where
string > "aaaa" and
vstring > "aaaa" and
bin > "aaaa" and
vbin > "aaaa" and
/* bin > "aaaa" and
vbin > "aaaa" and */
tiny < -1 and
short < -1 and
medium < -1 and
......@@ -345,8 +369,8 @@ auto
select auto from t1 where
string >= "aaaa" and
vstring >= "aaaa" and
bin >= "aaaa" and
vbin >= "aaaa" and
/* bin >= "aaaa" and
vbin >= "aaaa" and */
tiny <= -1 and
short <= -1 and
medium <= -1 and
......@@ -376,8 +400,8 @@ auto
select auto from t1 where
string < "dddd" and
vstring < "dddd" and
bin < "dddd" and
vbin < "dddd" and
/* bin < "dddd" and
vbin < "dddd" and */
tiny > -4 and
short > -4 and
medium > -4 and
......@@ -406,8 +430,8 @@ auto
select auto from t1 where
string <= "dddd" and
vstring <= "dddd" and
bin <= "dddd" and
vbin <= "dddd" and
/* bin <= "dddd" and
vbin <= "dddd" and */
tiny >= -4 and
short >= -4 and
medium >= -4 and
......@@ -438,8 +462,8 @@ create index medium_index on t1(medium);
select auto from t1 where
string = "aaaa" and
vstring = "aaaa" and
bin = "aaaa" and
vbin = "aaaa" and
/* bin = "aaaa" and
vbin = "aaaa" and */
tiny = -1 and
short = -1 and
medium = -1 and
......@@ -466,8 +490,8 @@ auto
select auto from t1 where
string != "aaaa" and
vstring != "aaaa" and
bin != "aaaa" and
vbin != "aaaa" and
/* bin != "aaaa" and
vbin != "aaaa" and */
tiny != -1 and
short != -1 and
medium != -1 and
......@@ -496,8 +520,8 @@ auto
select auto from t1 where
string > "aaaa" and
vstring > "aaaa" and
bin > "aaaa" and
vbin > "aaaa" and
/* bin > "aaaa" and
vbin > "aaaa" and */
tiny < -1 and
short < -1 and
medium < -1 and
......@@ -526,8 +550,8 @@ auto
select auto from t1 where
string >= "aaaa" and
vstring >= "aaaa" and
bin >= "aaaa" and
vbin >= "aaaa" and
/* bin >= "aaaa" and
vbin >= "aaaa" and */
tiny <= -1 and
short <= -1 and
medium <= -1 and
......@@ -557,8 +581,8 @@ auto
select auto from t1 where
string < "dddd" and
vstring < "dddd" and
bin < "dddd" and
vbin < "dddd" and
/* bin < "dddd" and
vbin < "dddd" and */
tiny > -4 and
short > -4 and
medium > -4 and
......@@ -587,8 +611,8 @@ auto
select auto from t1 where
string <= "dddd" and
vstring <= "dddd" and
bin <= "dddd" and
vbin <= "dddd" and
/* bin <= "dddd" and
vbin <= "dddd" and */
tiny >= -4 and
short >= -4 and
medium >= -4 and
......@@ -615,17 +639,41 @@ auto
2
3
4
select auto from t1 where
string like "b%" and
vstring like "b%" /* and
bin like "b%" and
vbin like "b%" */
order by auto;
auto
2
select auto from t1 where
string not like "b%" and
vstring not like "b%"/* and
bin not like "b%" and
vbin not like "b%" */
order by auto;
auto
1
3
4
select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
pk1 attr1 attr2 attr3
2 2 NULL NULL
3 3 3 d
select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
pk1 attr1 attr2 attr3
3 3 3 d
4 4 4 e
5 5 5 f
select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
pk1 attr1 attr2 attr3 attr4
2 2 9223372036854775804 2 c
4 4 9223372036854775806 4 e
5 5 9223372036854775807 5 f
select * from t2,t3 where t2.attr1 > 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
pk1 attr1 attr2 attr3 pk1 attr1 attr2 attr3 attr4
0 0 0 a 0 0 0 0 a
select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
pk1 attr1 attr2 attr3 attr4
2 2 9223372036854775804 2 c
......@@ -635,5 +683,15 @@ pk1 attr1 attr2 attr3 attr4 pk1 attr1 attr2 attr3 attr4
2 2 9223372036854775804 2 c 2 2 9223372036854775804 2 c
3 3 9223372036854775805 3 d 3 3 9223372036854775805 3 d
4 4 9223372036854775806 4 e 4 4 9223372036854775806 4 e
select auto from t1 where string = "aaaa" collate latin1_general_ci order by auto;
auto
1
select * from t2 where (attr1 < 2) = (attr2 < 2) order by pk1;
pk1 attr1 attr2 attr3
0 0 0 a
1 1 1 b
3 3 3 d
4 4 4 e
5 5 5 f
set engine_condition_pushdown = @old_ecpd;
DROP TABLE t1,t2,t3,t4;
......@@ -9,10 +9,10 @@ DROP TABLE IF EXISTS t1,t2;
#
CREATE TABLE t1 (
auto int(5) unsigned NOT NULL auto_increment,
string char(10) default "hello",
vstring varchar(10) default "hello",
bin binary(7) default "hello",
vbin varbinary(7) default "hello",
string char(10),
vstring varchar(10),
bin binary(7),
vbin varbinary(7),
tiny tinyint(4) DEFAULT '0' NOT NULL ,
short smallint(6) DEFAULT '1' NOT NULL ,
medium mediumint(8) DEFAULT '0' NOT NULL,
......@@ -233,10 +233,26 @@ time_field <= '04:04:04' and
date_time <= '1904-04-04 04:04:04'
order by auto;
# Test LIKE/NOT LIKE
select auto from t1 where
string like "b%" and
vstring like "b%" and
bin like "b%" and
vbin like "b%"
order by auto;
select auto from t1 where
string not like "b%" and
vstring not like "b%" and
bin not like "b%" and
vbin not like "b%"
order by auto;
# Various tests
select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
select * from t2,t3 where t2.attr1 > 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
......@@ -246,8 +262,8 @@ set engine_condition_pushdown = on;
select auto from t1 where
string = "aaaa" and
vstring = "aaaa" and
bin = "aaaa" and
vbin = "aaaa" and
/* bin = "aaaa" and
vbin = "aaaa" and */
tiny = -1 and
short = -1 and
medium = -1 and
......@@ -273,8 +289,8 @@ order by auto;
select auto from t1 where
string != "aaaa" and
vstring != "aaaa" and
bin != "aaaa" and
vbin != "aaaa" and
/* bin != "aaaa" and
vbin != "aaaa" and */
tiny != -1 and
short != -1 and
medium != -1 and
......@@ -300,8 +316,8 @@ order by auto;
select auto from t1 where
string > "aaaa" and
vstring > "aaaa" and
bin > "aaaa" and
vbin > "aaaa" and
/* bin > "aaaa" and
vbin > "aaaa" and */
tiny < -1 and
short < -1 and
medium < -1 and
......@@ -327,8 +343,8 @@ order by auto;
select auto from t1 where
string >= "aaaa" and
vstring >= "aaaa" and
bin >= "aaaa" and
vbin >= "aaaa" and
/* bin >= "aaaa" and
vbin >= "aaaa" and */
tiny <= -1 and
short <= -1 and
medium <= -1 and
......@@ -354,8 +370,8 @@ order by auto;
select auto from t1 where
string < "dddd" and
vstring < "dddd" and
bin < "dddd" and
vbin < "dddd" and
/* bin < "dddd" and
vbin < "dddd" and */
tiny > -4 and
short > -4 and
medium > -4 and
......@@ -381,8 +397,8 @@ order by auto;
select auto from t1 where
string <= "dddd" and
vstring <= "dddd" and
bin <= "dddd" and
vbin <= "dddd" and
/* bin <= "dddd" and
vbin <= "dddd" and */
tiny >= -4 and
short >= -4 and
medium >= -4 and
......@@ -412,8 +428,8 @@ create index medium_index on t1(medium);
select auto from t1 where
string = "aaaa" and
vstring = "aaaa" and
bin = "aaaa" and
vbin = "aaaa" and
/* bin = "aaaa" and
vbin = "aaaa" and */
tiny = -1 and
short = -1 and
medium = -1 and
......@@ -439,8 +455,8 @@ order by auto;
select auto from t1 where
string != "aaaa" and
vstring != "aaaa" and
bin != "aaaa" and
vbin != "aaaa" and
/* bin != "aaaa" and
vbin != "aaaa" and */
tiny != -1 and
short != -1 and
medium != -1 and
......@@ -466,8 +482,8 @@ order by auto;
select auto from t1 where
string > "aaaa" and
vstring > "aaaa" and
bin > "aaaa" and
vbin > "aaaa" and
/* bin > "aaaa" and
vbin > "aaaa" and */
tiny < -1 and
short < -1 and
medium < -1 and
......@@ -493,8 +509,8 @@ order by auto;
select auto from t1 where
string >= "aaaa" and
vstring >= "aaaa" and
bin >= "aaaa" and
vbin >= "aaaa" and
/* bin >= "aaaa" and
vbin >= "aaaa" and */
tiny <= -1 and
short <= -1 and
medium <= -1 and
......@@ -520,8 +536,8 @@ order by auto;
select auto from t1 where
string < "dddd" and
vstring < "dddd" and
bin < "dddd" and
vbin < "dddd" and
/* bin < "dddd" and
vbin < "dddd" and */
tiny > -4 and
short > -4 and
medium > -4 and
......@@ -547,8 +563,8 @@ order by auto;
select auto from t1 where
string <= "dddd" and
vstring <= "dddd" and
bin <= "dddd" and
vbin <= "dddd" and
/* bin <= "dddd" and
vbin <= "dddd" and */
tiny >= -4 and
short >= -4 and
medium >= -4 and
......@@ -571,11 +587,32 @@ time_field <= '04:04:04' and
date_time <= '1904-04-04 04:04:04'
order by auto;
# Test LIKE/NOT LIKE
select auto from t1 where
string like "b%" and
vstring like "b%" /* and
bin like "b%" and
vbin like "b%" */
order by auto;
select auto from t1 where
string not like "b%" and
vstring not like "b%"/* and
bin not like "b%" and
vbin not like "b%" */
order by auto;
# Various tests
select * from t2 where attr3 is null or attr1 > 2 and pk1= 3 order by pk1;
select * from t2 where attr3 is not null and attr1 > 2 order by pk1;
select * from t3 where attr2 > 9223372036854775803 and attr3 != 3 order by pk1;
select * from t2,t3 where t2.attr1 > 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
select * from t2,t3 where t2.attr1 < 1 and t2.attr2 = t3.attr2 and t3.attr1 < 5 order by t2.pk1;
select * from t4 where attr1 < 5 and attr2 > 9223372036854775803 and attr3 != 3 order by t4.pk1;
select * from t3,t4 where t4.attr1 > 1 and t4.attr2 = t3.attr2 and t4.attr3 < 5 order by t4.pk1;
# Some tests that are currently not supported and should not push condition
select auto from t1 where string = "aaaa" collate latin1_general_ci order by auto;
select * from t2 where (attr1 < 2) = (attr2 < 2) order by pk1;
set engine_condition_pushdown = @old_ecpd;
DROP TABLE t1,t2,t3,t4;
......@@ -5930,6 +5930,7 @@ void ndb_serialize_cond(const Item *item, void *arg)
// Expect char string or binary string
context->expect_only(Item::STRING_ITEM);
context->expect(Item::VARBIN_ITEM);
context->expect_collation(field_item->collation.collation);
break;
case(REAL_RESULT):
context->expect_only(Item::REAL_ITEM);
......@@ -5945,7 +5946,22 @@ void ndb_serialize_cond(const Item *item, void *arg)
break;
default:
break;
}
}
}
else
{
// Expect another logical expression
context->expect_only(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
// Check that field and string constant collations are the same
if ((field->result_type() == STRING_RESULT) &&
!context->expecting_collation(item->collation.collation))
{
DBUG_PRINT("info", ("Found non-matching collations %s and %s",
item->collation.collation->name,
context->collation->name));
context->supported= FALSE;
}
}
break;
}
......@@ -5957,12 +5973,22 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item::FUNC_ITEM): {
Item_func *func_item= (Item_func *) item;
// Check that we expect a function or functional expression here
if (context->expecting(Item::FUNC_ITEM) ||
func_item->functype() == Item_func::UNKNOWN_FUNC)
context->expect_nothing();
else
{
// Did not expect function here
context->supported= FALSE;
break;
}
context->expect_nothing();
switch(func_item->functype()) {
case(Item_func::EQ_FUNC): {
DBUG_PRINT("info", ("EQ_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::INT_ITEM);
context->expect(Item::REAL_ITEM);
......@@ -5977,7 +6003,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::NE_FUNC): {
DBUG_PRINT("info", ("NE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::INT_ITEM);
context->expect(Item::REAL_ITEM);
......@@ -5992,7 +6019,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::LT_FUNC): {
DBUG_PRINT("info", ("LT_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::INT_ITEM);
context->expect(Item::REAL_ITEM);
......@@ -6007,7 +6035,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::LE_FUNC): {
DBUG_PRINT("info", ("LE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::INT_ITEM);
context->expect(Item::REAL_ITEM);
......@@ -6022,7 +6051,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::GE_FUNC): {
DBUG_PRINT("info", ("GE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::INT_ITEM);
context->expect(Item::REAL_ITEM);
......@@ -6037,7 +6067,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::GT_FUNC): {
DBUG_PRINT("info", ("GT_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::REAL_ITEM);
context->expect(Item::DECIMAL_ITEM);
......@@ -6052,7 +6083,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::LIKE_FUNC): {
DBUG_PRINT("info", ("LIKE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::FIELD_ITEM);
context->expect_field_result(STRING_RESULT);
......@@ -6060,7 +6092,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::NOTLIKE_FUNC): {
DBUG_PRINT("info", ("NOTLIKE_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::STRING_ITEM);
context->expect(Item::FIELD_ITEM);
context->expect_field_result(STRING_RESULT);
......@@ -6068,7 +6101,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::ISNULL_FUNC): {
DBUG_PRINT("info", ("ISNULL_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::FIELD_ITEM);
context->expect_field_result(STRING_RESULT);
context->expect_field_result(REAL_RESULT);
......@@ -6078,7 +6112,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::ISNOTNULL_FUNC): {
DBUG_PRINT("info", ("ISNOTNULL_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::FIELD_ITEM);
context->expect_field_result(STRING_RESULT);
context->expect_field_result(REAL_RESULT);
......@@ -6088,7 +6123,8 @@ void ndb_serialize_cond(const Item *item, void *arg)
}
case(Item_func::NOT_FUNC): {
DBUG_PRINT("info", ("NOT_FUNC"));
curr_cond->ndb_item= new Ndb_item(func_item->functype());
curr_cond->ndb_item= new Ndb_item(func_item->functype(),
func_item);
context->expect(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
break;
......@@ -6102,16 +6138,28 @@ void ndb_serialize_cond(const Item *item, void *arg)
case(STRING_RESULT): {
NDB_ITEM_QUALIFICATION q;
q.value_type= Item::STRING_ITEM;
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
if (context->expect_field_result_mask)
{
// 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
context->expect_nothing();
{
// 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 collations %s and %s",
item->collation.collation->name,
context->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();
......@@ -6128,7 +6176,11 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_only_field_result(REAL_RESULT);
}
else
context->expect_nothing();
{
// 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"));
......@@ -6146,7 +6198,11 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_only_field_result(INT_RESULT);
}
else
context->expect_nothing();
{
// 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"));
......@@ -6164,8 +6220,11 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_only_field_result(DECIMAL_RESULT);
}
else
context->expect_nothing();
{
// 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();
......@@ -6207,9 +6266,22 @@ void ndb_serialize_cond(const Item *item, void *arg)
// 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
context->expect_nothing();
{
// Expect another logical expression
context->expect_only(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
// Check that we are comparing with a field with same collation
if (!context->expecting_collation(item->collation.collation))
{
DBUG_PRINT("info", ("Found non-matching collations %s and %s",
item->collation.collation->name,
context->collation->name));
context->supported= FALSE;
}
}
}
else
context->supported= FALSE;
......@@ -6230,7 +6302,11 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_only_field_result(INT_RESULT);
}
else
context->expect_nothing();
{
// Expect another logical expression
context->expect_only(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
}
}
else
context->supported= FALSE;
......@@ -6251,7 +6327,11 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_only_field_result(REAL_RESULT);
}
else
context->expect_nothing();
{
// Expect another logical expression
context->expect_only(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
}
}
else
context->supported= FALSE;
......@@ -6278,7 +6358,11 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_only_field_result(STRING_RESULT);
}
else
context->expect_nothing();
{
// Expect another logical expression
context->expect_only(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
}
}
else
context->supported= FALSE;
......@@ -6300,27 +6384,38 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->expect_field_result(DECIMAL_RESULT);
}
else
context->expect_nothing();
{
// Expect another logical expression
context->expect_only(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
}
}
else
context->supported= FALSE;
break;
case(Item::COND_ITEM): {
Item_cond *cond_item= (Item_cond *) item;
switch(cond_item->functype()) {
case(Item_func::COND_AND_FUNC):
DBUG_PRINT("info", ("COND_AND_FUNC"));
curr_cond->ndb_item= new Ndb_item(cond_item->functype());
break;
case(Item_func::COND_OR_FUNC):
DBUG_PRINT("info", ("COND_OR_FUNC"));
curr_cond->ndb_item= new Ndb_item(cond_item->functype());
break;
default:
DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype()));
context->supported= FALSE;
break;
}
if (context->expecting(Item::COND_ITEM))
switch(cond_item->functype()) {
case(Item_func::COND_AND_FUNC):
DBUG_PRINT("info", ("COND_AND_FUNC"));
curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
cond_item);
break;
case(Item_func::COND_OR_FUNC):
DBUG_PRINT("info", ("COND_OR_FUNC"));
curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
cond_item);
break;
default:
DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype()));
context->supported= FALSE;
break;
}
else
// Did not expect condition
context->supported= FALSE;
break;
}
default: {
......@@ -6339,6 +6434,9 @@ ha_ndbcluster::serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond)
DBUG_ENTER("serialize_cond");
Item *item= (Item *) cond;
Ndb_cond_traverse_context context(table, (void *)m_table, ndb_cond);
// Expect a logical expression
context.expect(Item::FUNC_ITEM);
context.expect(Item::COND_ITEM);
item->traverse_cond(&ndb_serialize_cond, (void *) &context, Item::PREFIX);
DBUG_PRINT("info", ("The pushed condition is %ssupported", (context.supported)?"":"not "));
......@@ -6356,22 +6454,33 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
if (!cond->next)
break;
Ndb_item *a= cond->next->ndb_item;
switch((negated) ?
Ndb_item::negate(cond->ndb_item->qualification.function_type)
: cond->ndb_item->qualification.function_type)
{
case(Item_func::EQ_FUNC): {
Ndb_item *b, *field, *value= NULL;
switch(cond->ndb_item->argument_count()) {
case(1):
field=
(a->type == NDB_FIELD)? a : NULL;
break;
case(2):
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
b= cond->next->next->ndb_item;
value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
break;
deafult:
break;
}
switch((negated) ?
Ndb_item::negate(cond->ndb_item->qualification.function_type)
: cond->ndb_item->qualification.function_type)
{
case(Item_func::EQ_FUNC): {
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
......@@ -6385,17 +6494,6 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(0);
}
case(Item_func::NE_FUNC): {
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
......@@ -6409,17 +6507,6 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(0);
}
case(Item_func::LT_FUNC): {
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
......@@ -6445,17 +6532,6 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(0);
}
case(Item_func::LE_FUNC): {
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
......@@ -6481,17 +6557,6 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(0);
}
case(Item_func::GE_FUNC): {
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
......@@ -6517,17 +6582,6 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(0);
}
case(Item_func::GT_FUNC): {
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
if (!value || !field) break;
// Save value in right format for the field type
value->save_in_field(field);
......@@ -6553,17 +6607,6 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
DBUG_RETURN(0);
}
case(Item_func::LIKE_FUNC): {
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
if (!value || !field) break;
if (value->qualification.value_type != Item::STRING_ITEM) break;
// Save value in right format for the field type
......@@ -6573,24 +6616,13 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
value->pack_length()));
if (filter->cmp(NdbScanFilter::COND_LIKE,
field->get_field_no(),
field->get_val(),
field->pack_length()) == -1)
value->get_val(),
value->pack_length()) == -1)
DBUG_RETURN(1);
cond= cond->next->next->next;
DBUG_RETURN(0);
}
case(Item_func::NOTLIKE_FUNC): {
if (!cond->next->next)
break;
Ndb_item *b= cond->next->next->ndb_item;
Ndb_item *value=
(a->type == NDB_VALUE)? a
: (b->type == NDB_VALUE)? b
: NULL;
Ndb_item *field=
(a->type == NDB_FIELD)? a
: (b->type == NDB_FIELD)? b
: NULL;
if (!value || !field) break;
if (value->qualification.value_type != Item::STRING_ITEM) break;
// Save value in right format for the field type
......@@ -6600,28 +6632,26 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
value->pack_length()));
if (filter->cmp(NdbScanFilter::COND_NOT_LIKE,
field->get_field_no(),
field->get_val(),
field->pack_length()) == -1)
value->get_val(),
value->pack_length()) == -1)
DBUG_RETURN(1);
cond= cond->next->next->next;
DBUG_RETURN(0);
}
case(Item_func::ISNULL_FUNC):
if (a->type == NDB_FIELD)
{
DBUG_PRINT("info", ("Generating ISNULL filter"));
if (filter->isnull(a->get_field_no()) == -1)
DBUG_RETURN(1);
}
if (!field)
break;
DBUG_PRINT("info", ("Generating ISNULL filter"));
if (filter->isnull(field->get_field_no()) == -1)
DBUG_RETURN(1);
cond= cond->next->next;
DBUG_RETURN(0);
case(Item_func::ISNOTNULL_FUNC): {
if (a->type == NDB_FIELD)
{
DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
if (filter->isnotnull(a->get_field_no()) == -1)
DBUG_RETURN(1);
}
if (!field)
break;
DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
if (filter->isnotnull(field->get_field_no()) == -1)
DBUG_RETURN(1);
cond= cond->next->next;
DBUG_RETURN(0);
}
......@@ -6638,62 +6668,64 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
}
int
ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter,
bool negated)
ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
{
uint level=0;
bool negated= false;
DBUG_ENTER("build_scan_filter_group");
if (!cond) DBUG_RETURN(1);
switch(cond->ndb_item->type) {
case(NDB_FUNCTION):
switch(cond->ndb_item->qualification.function_type) {
case(Item_func::COND_AND_FUNC): {
DBUG_PRINT("info", ("Generating %s group", (negated)?"NAND":"AND"));
if ((negated) ? filter->begin(NdbScanFilter::NAND)
: filter->begin(NdbScanFilter::AND) == -1)
DBUG_RETURN(1);
cond= cond->next;
do
{
if (build_scan_filter_group(cond, filter))
do
{
if (!cond) DBUG_RETURN(1);
switch(cond->ndb_item->type) {
case(NDB_FUNCTION):
switch(cond->ndb_item->qualification.function_type) {
case(Item_func::COND_AND_FUNC): {
level++;
DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND",
level));
if ((negated) ? filter->begin(NdbScanFilter::NAND)
: filter->begin(NdbScanFilter::AND) == -1)
DBUG_RETURN(1);
} while (cond && cond->ndb_item->type != NDB_END_COND);
if (cond) cond= cond->next;
if (filter->end() == -1)
DBUG_RETURN(1);
DBUG_PRINT("info", ("End of %s group", (negated)?"NAND":"AND"));
break;
}
case(Item_func::COND_OR_FUNC): {
DBUG_PRINT("info", ("Generating % group", (negated)?"NOR":"OR"));
if ((negated) ? filter->begin(NdbScanFilter::NOR)
: filter->begin(NdbScanFilter::OR) == -1)
DBUG_RETURN(1);
cond= cond->next;
do
{
if (build_scan_filter_group(cond, filter))
negated= false;
cond= cond->next;
break;
}
case(Item_func::COND_OR_FUNC): {
level++;
DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR",
level));
if ((negated) ? filter->begin(NdbScanFilter::NOR)
: filter->begin(NdbScanFilter::OR) == -1)
DBUG_RETURN(1);
negated= false;
cond= cond->next;
break;
}
case(Item_func::NOT_FUNC): {
cond= cond->next;
negated= true;
break;
}
default:
if (build_scan_filter_predicate(cond, filter, negated))
DBUG_RETURN(1);
} while (cond && cond->ndb_item->type != NDB_END_COND);
negated= false;
break;
}
break;
case(NDB_END_COND):
DBUG_PRINT("info", ("End of group %u", level));
level--;
if (cond) cond= cond->next;
if (filter->end() == -1)
DBUG_RETURN(1);
DBUG_PRINT("info", ("End of %s group", (negated)?"NOR":"OR"));
break;
default: {
DBUG_PRINT("info", ("Illegal scan filter"));
}
case(Item_func::NOT_FUNC): {
cond= cond->next;
build_scan_filter_group(cond, filter, true);
break;
}
default:
if (build_scan_filter_predicate(cond, filter, negated))
DBUG_RETURN(1);
}
break;
default: {
DBUG_PRINT("info", ("Illegal scan filter"));
}
}
} while (level > 0);
DBUG_RETURN(0);
}
......@@ -6706,8 +6738,6 @@ ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter)
switch(cond->ndb_item->type) {
case(Item_func::COND_AND_FUNC):
simple_cond= FALSE;
break;
case(Item_func::COND_OR_FUNC):
simple_cond= FALSE;
break;
......
......@@ -109,10 +109,18 @@ static const negated_function_mapping neg_map[]=
};
/*
This class is used for serialization of the Item tree for
condition pushdown. It is stored in a linked list implemented
by Ndb_cond class.
*/
This class is the construction element for serialization of Item tree
in condition pushdown.
An instance of Ndb_Item represents a constant, table field reference,
unary or binary comparison predicate, and start/end of AND/OR.
Instances of Ndb_Item are stored in a linked list implemented by Ndb_cond
class.
The order of elements produced by Ndb_cond::next corresponds to
depth-first traversal of the Item (i.e. expression) tree in prefix order.
AND and OR have arbitrary arity, so the end of AND/OR group is marked with
Ndb_item with type == NDB_END_COND.
NOT items represent negated conditions and generate NAND/NOR groups.
*/
class Ndb_item {
public:
Ndb_item(NDB_ITEM_TYPE item_type) : type(item_type) {};
......@@ -134,6 +142,8 @@ class Ndb_item {
break;
}
case(NDB_FUNCTION):
value.item= item_value;
break;
case(NDB_END_COND):
break;
}
......@@ -146,9 +156,11 @@ class Ndb_item {
field_value->column_no= column_no;
value.field_value= field_value;
};
Ndb_item(Item_func::Functype func_type) : type(NDB_FUNCTION)
Ndb_item(Item_func::Functype func_type, const Item *item_value)
: type(NDB_FUNCTION)
{
qualification.function_type= func_type;
value.item= item_value;
};
~Ndb_item()
{
......@@ -179,6 +191,11 @@ class Ndb_item {
int get_field_no() { return value.field_value->column_no; };
int argument_count()
{
return ((Item_func *) value.item)->argument_count();
};
const char* get_val()
{
switch(type) {
......@@ -274,7 +291,7 @@ class Ndb_cond_traverse_context
Ndb_cond_traverse_context(TABLE *tab, void* ndb_tab, Ndb_cond_stack* stack)
: table(tab), ndb_table(ndb_tab),
supported(TRUE), stack_ptr(stack), cond_ptr(NULL),
expect_mask(0), expect_field_result_mask(0), skip(0)
expect_mask(0), expect_field_result_mask(0), skip(0), collation(NULL)
{
if (stack)
cond_ptr= stack->ndb_cond;
......@@ -318,6 +335,17 @@ class Ndb_cond_traverse_context
expect_field_result_mask= 0;
expect_field_result(result);
};
void expect_collation(CHARSET_INFO* col)
{
collation= col;
};
bool expecting_collation(CHARSET_INFO* col)
{
bool matching= (!collation) ? true : (collation == col);
collation= NULL;
return matching;
};
TABLE* table;
void* ndb_table;
......@@ -327,6 +355,8 @@ class Ndb_cond_traverse_context
uint expect_mask;
uint expect_field_result_mask;
uint skip;
CHARSET_INFO* collation;
};
/*
......@@ -428,27 +458,40 @@ class ha_ndbcluster: public handler
/*
Condition pushdown
*/
/*
Push a condition to ndbcluster storage engine for evaluation
during table and index scans. The conditions will be stored on a stack
for possibly storing several conditions. The stack can be popped
by calling cond_pop, handler::extra(HA_EXTRA_RESET) (handler::reset())
will clear the stack.
The current implementation supports arbitrary AND/OR nested conditions
with comparisons between columns and constants (including constant
expressions and function calls) and the following comparison operators:
=, !=, >, >=, <, <=, "is null", and "is not null".
RETURN
NULL The condition was supported and will be evaluated for each
row found during the scan
cond The condition was not supported and all rows will be returned from
the scan for evaluation (and thus not saved on stack)
*/
/*
Push condition down to the table handler.
SYNOPSIS
cond_push()
cond Condition to be pushed. The condition tree must not be
modified by the by the caller.
RETURN
The 'remainder' condition that caller must use to filter out records.
NULL means the handler will not return rows that do not match the
passed condition.
NOTES
The pushed conditions form a stack (from which one can remove the
last pushed condition using cond_pop).
The table handler filters out rows using (pushed_cond1 AND pushed_cond2
AND ... AND pushed_condN)
or less restrictive condition, depending on handler's capabilities.
handler->extra(HA_EXTRA_RESET) call empties the condition stack.
Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
condition stack.
The current implementation supports arbitrary AND/OR nested conditions
with comparisons between columns and constants (including constant
expressions and function calls) and the following comparison operators:
=, !=, >, >=, <, <=, like, "not like", "is null", and "is not null".
Negated conditions are supported by NOT which generate NAND/NOR groups.
*/
const COND *cond_push(const COND *cond);
/*
Pop the top condition from the condition stack of the handler instance.
*/
/*
Pop the top condition from the condition stack of the handler instance.
SYNOPSIS
cond_pop()
Pops the top if condition stack, if stack is not empty
*/
void cond_pop();
uint8 table_cache_type();
......@@ -536,8 +579,7 @@ private:
NdbScanFilter* filter,
bool negated= false);
int build_scan_filter_group(Ndb_cond* &cond,
NdbScanFilter* filter,
bool negated= false);
NdbScanFilter* filter);
int build_scan_filter(Ndb_cond* &cond, NdbScanFilter* filter);
int generate_scan_filter(Ndb_cond_stack* cond_stack,
NdbScanOperation* op);
......
......@@ -451,7 +451,7 @@ public:
enum {NONE=0, INDEX, RND} inited;
bool auto_increment_column_changed;
bool implicit_emptied; /* Can be !=0 only if HEAP */
const COND *pushed_cond;
handler(TABLE *table_arg) :table(table_arg),
ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0),
......@@ -460,7 +460,8 @@ public:
create_time(0), check_time(0), update_time(0),
key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
ref_length(sizeof(my_off_t)), block_size(0),
raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0)
raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0),
pushed_cond(NULL)
{}
virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
int ha_open(const char *name, int mode, int test_if_locked);
......@@ -724,23 +725,34 @@ public:
Condition pushdown to storage engines
*/
/*
Push a condition to storage engine for evaluation during table
and index scans. The conditions should be stored on a stack
for possibly storing several conditions. The stack can be popped
by calling cond_pop, handler::extra(HA_EXTRA_RESET) (handler::reset())
should clear the stack.
The condition can be traversed using Item::traverse_cond
RETURN
NULL The condition was supported by the handler and will be evaluated
for each row found during the scan
cond The condition was not supported and all rows will be returned from
the scan for evaluation (and thus not saved on stack)
*/
/*
Push condition down to the table handler.
SYNOPSIS
cond_push()
cond Condition to be pushed. The condition tree must not be
modified by the by the caller.
RETURN
The 'remainder' condition that caller must use to filter out records.
NULL means the handler will not return rows that do not match the
passed condition.
NOTES
The pushed conditions form a stack (from which one can remove the
last pushed condition using cond_pop).
The table handler filters out rows using (pushed_cond1 AND pushed_cond2
AND ... AND pushed_condN)
or less restrictive condition, depending on handler's capabilities.
handler->extra(HA_EXTRA_RESET) call empties the condition stack.
Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
condition stack.
*/
virtual const COND *cond_push(const COND *cond) { return cond; };
/*
Pop the top condition from the condition stack of the handler instance.
*/
/*
Pop the top condition from the condition stack of the handler instance.
SYNOPSIS
cond_pop()
Pops the top if condition stack, if stack is not empty
*/
virtual void cond_pop() { return; };
};
......
......@@ -5305,7 +5305,12 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
DBUG_RETURN(1);
tab->select_cond=sel->cond=tmp;
if (current_thd->variables.engine_condition_pushdown)
tab->table->file->cond_push(tmp); // Push condition to handler
{
tab->table->file->pushed_cond= NULL;
/* Push condition to handler */
if (!tab->table->file->cond_push(tmp))
tab->table->file->pushed_cond= tmp;
}
}
else
tab->select_cond= sel->cond= NULL;
......@@ -5428,8 +5433,12 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tab->cache.select->cond=tmp;
tab->cache.select->read_tables=join->const_table_map;
if (current_thd->variables.engine_condition_pushdown &&
(tmp != tab->select_cond))
tab->table->file->cond_push(tmp); // Push condition to handler
(!tab->table->file->pushed_cond))
{
/* Push condition to handler */
if (!tab->table->file->cond_push(tmp))
tab->table->file->pushed_cond= tmp;
}
}
}
}
......
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