diff options
author | bell@sanja.is.com.ua <> | 2002-12-10 11:45:40 +0200 |
---|---|---|
committer | bell@sanja.is.com.ua <> | 2002-12-10 11:45:40 +0200 |
commit | 2885d552613c402d91da21717efa7b0220702aa8 (patch) | |
tree | f6ca7aa660a25caf3c2288ff373f1cb799f4e33b | |
parent | 6db77efb75cc0e0999fa515f4d2fbc2fcc7f1625 (diff) | |
parent | 3172a45149140b60db335d1186b0bae54357b59b (diff) | |
download | mariadb-git-2885d552613c402d91da21717efa7b0220702aa8.tar.gz |
merging
-rw-r--r-- | mysql-test/r/row.result | 130 | ||||
-rw-r--r-- | mysql-test/r/row_test.result | 60 | ||||
-rw-r--r-- | mysql-test/t/row.test | 59 | ||||
-rw-r--r-- | mysql-test/t/row_test.test | 36 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 199 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 213 | ||||
-rw-r--r-- | sql/item_row.cc | 23 | ||||
-rw-r--r-- | sql/item_row.h | 12 | ||||
-rw-r--r-- | sql/sql_list.h | 10 | ||||
-rw-r--r-- | sql/sql_select.cc | 10 |
10 files changed, 574 insertions, 178 deletions
diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result new file mode 100644 index 00000000000..e0b524d9bb2 --- /dev/null +++ b/mysql-test/r/row.result @@ -0,0 +1,130 @@ +select row(1,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +row(1,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)) +1 +select row(10,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +row(10,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)) +0 +select row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) +1 +select row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) +NULL +select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')); +row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')) +1 +select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)); +row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)) +1 +select row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3)); +row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3)) +1 +select row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)) +1 +select row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)) +NULL +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))); +row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))) +1 +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,4)); +Cardinality error (more/less than 2 columns) +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); +row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))) +NULL +SELECT ROW(1,2,3)=ROW(1,2,3); +ROW(1,2,3)=ROW(1,2,3) +1 +SELECT ROW(2,2,3)=ROW(1+1,2,3); +ROW(2,2,3)=ROW(1+1,2,3) +1 +SELECT ROW(1,2,3)=ROW(1+1,2,3); +ROW(1,2,3)=ROW(1+1,2,3) +0 +SELECT ROW(1,2,3)<ROW(1+1,2,3); +ROW(1,2,3)<ROW(1+1,2,3) +1 +SELECT ROW(1,2,3)>ROW(1+1,2,3); +ROW(1,2,3)>ROW(1+1,2,3) +0 +SELECT ROW(1,2,3)<=ROW(1+1,2,3); +ROW(1,2,3)<=ROW(1+1,2,3) +1 +SELECT ROW(1,2,3)>=ROW(1+1,2,3); +ROW(1,2,3)>=ROW(1+1,2,3) +0 +SELECT ROW(1,2,3)<>ROW(1+1,2,3); +ROW(1,2,3)<>ROW(1+1,2,3) +1 +SELECT ROW(NULL,2,3)=ROW(NULL,2,3); +ROW(NULL,2,3)=ROW(NULL,2,3) +NULL +SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); +ROW(NULL,2,3)<=>ROW(NULL,2,3) +1 +SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); +ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)) +1 +SELECT ROW('test',2,3.33)=ROW('test',2,3.33); +ROW('test',2,3.33)=ROW('test',2,3.33) +1 +SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); +Cardinality error (more/less than 3 columns) +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)); +ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)) +1 +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,3)); +ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,3)) +0 +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)); +ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)) +NULL +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,4); +Cardinality error (more/less than 2 columns) +drop table if exists t1; +create table t1 ( a int, b int, c int); +insert into t1 values (1,2,3), (2,3,1), (3,2,1), (1,2,NULL); +select * from t1 where ROW(1,2,3)=ROW(a,b,c); +a b c +1 2 3 +select * from t1 where ROW(0,2,3)=ROW(a,b,c); +a b c +select * from t1 where ROW(1,2,3)<ROW(a,b,c); +a b c +2 3 1 +3 2 1 +select ROW(a,2,3) IN(row(1,b,c), row(2,3,1)) from t1; +ROW(a,2,3) IN(row(1,b,c), row(2,3,1)) +1 +0 +0 +NULL +select ROW(c,2,3) IN(row(1,b,a), row(2,3,1)) from t1; +ROW(c,2,3) IN(row(1,b,a), row(2,3,1)) +0 +0 +1 +NULL +select ROW(a,b,c) IN(row(1,2,3), row(3,2,1)) from t1; +ROW(a,b,c) IN(row(1,2,3), row(3,2,1)) +1 +0 +1 +NULL +select ROW(1,2,3) IN(row(a,b,c), row(1,2,3)) from t1; +ROW(1,2,3) IN(row(a,b,c), row(1,2,3)) +1 +1 +1 +1 +drop table t1; +select ROW(1,1); +Cardinality error (more/less than 1 columns) +drop table if exists t1; +create table t1 (i int); +select 1 from t1 where ROW(1,1); +Cardinality error (more/less than 1 columns) +select count(*) from t1 order by ROW(1,1); +Cardinality error (more/less than 1 columns) +drop table t1; diff --git a/mysql-test/r/row_test.result b/mysql-test/r/row_test.result deleted file mode 100644 index f6e989789c7..00000000000 --- a/mysql-test/r/row_test.result +++ /dev/null @@ -1,60 +0,0 @@ -SELECT ROW(1,2,3)=ROW(1,2,3); -ROW(1,2,3)=ROW(1,2,3) -1 -SELECT ROW(2,2,3)=ROW(1+1,2,3); -ROW(2,2,3)=ROW(1+1,2,3) -1 -SELECT ROW(1,2,3)=ROW(1+1,2,3); -ROW(1,2,3)=ROW(1+1,2,3) -0 -SELECT ROW(1,2,3)<ROW(1+1,2,3); -ROW(1,2,3)<ROW(1+1,2,3) -1 -SELECT ROW(1,2,3)>ROW(1+1,2,3); -ROW(1,2,3)>ROW(1+1,2,3) -0 -SELECT ROW(1,2,3)<=ROW(1+1,2,3); -ROW(1,2,3)<=ROW(1+1,2,3) -1 -SELECT ROW(1,2,3)>=ROW(1+1,2,3); -ROW(1,2,3)>=ROW(1+1,2,3) -0 -SELECT ROW(1,2,3)<>ROW(1+1,2,3); -ROW(1,2,3)<>ROW(1+1,2,3) -1 -SELECT ROW(NULL,2,3)=ROW(NULL,2,3); -ROW(NULL,2,3)=ROW(NULL,2,3) -NULL -SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); -ROW(NULL,2,3)<=>ROW(NULL,2,3) -1 -SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); -ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)) -1 -SELECT ROW('test',2,3.33)=ROW('test',2,3.33); -ROW('test',2,3.33)=ROW('test',2,3.33) -1 -SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); -Cardinality error (more/less than 3 columns) -drop table if exists t1; -create table t1 ( a int, b int, c int); -insert into t1 values (1,2,3), (2,3,1), (3,2,1); -select * from t1 where ROW(1,2,3)=ROW(a,b,c); -a b c -1 2 3 -select * from t1 where ROW(0,2,3)=ROW(a,b,c); -a b c -select * from t1 where ROW(1,2,3)<ROW(a,b,c); -a b c -2 3 1 -3 2 1 -drop table t1; -select ROW(1,1); -Cardinality error (more/less than 1 columns) -drop table if exists t1; -create table t1 (i int); -select 1 from t1 where ROW(1,1); -Cardinality error (more/less than 1 columns) -select count(*) from t1 order by ROW(1,1); -Cardinality error (more/less than 1 columns) -drop table t1; diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test new file mode 100644 index 00000000000..04f31fcbfe1 --- /dev/null +++ b/mysql-test/t/row.test @@ -0,0 +1,59 @@ +select row(1,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +select row(10,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +select row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +select row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')); +select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)); +select row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3)); +select row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +select row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))); +-- error 1239 +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,4)); +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); + +SELECT ROW(1,2,3)=ROW(1,2,3); +SELECT ROW(2,2,3)=ROW(1+1,2,3); +SELECT ROW(1,2,3)=ROW(1+1,2,3); +SELECT ROW(1,2,3)<ROW(1+1,2,3); +SELECT ROW(1,2,3)>ROW(1+1,2,3); +SELECT ROW(1,2,3)<=ROW(1+1,2,3); +SELECT ROW(1,2,3)>=ROW(1+1,2,3); +SELECT ROW(1,2,3)<>ROW(1+1,2,3); +SELECT ROW(NULL,2,3)=ROW(NULL,2,3); +SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); +SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); +SELECT ROW('test',2,3.33)=ROW('test',2,3.33); +-- error 1239 +SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)); +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,3)); +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)); +-- error 1239 +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,4); +drop table if exists t1; +create table t1 ( a int, b int, c int); +insert into t1 values (1,2,3), (2,3,1), (3,2,1), (1,2,NULL); +select * from t1 where ROW(1,2,3)=ROW(a,b,c); +select * from t1 where ROW(0,2,3)=ROW(a,b,c); +select * from t1 where ROW(1,2,3)<ROW(a,b,c); +select ROW(a,2,3) IN(row(1,b,c), row(2,3,1)) from t1; +select ROW(c,2,3) IN(row(1,b,a), row(2,3,1)) from t1; +select ROW(a,b,c) IN(row(1,2,3), row(3,2,1)) from t1; +select ROW(1,2,3) IN(row(a,b,c), row(1,2,3)) from t1; +drop table t1; + +-- error 1239 +select ROW(1,1); +drop table if exists t1; +create table t1 (i int); +-- error 1239 +select 1 from t1 where ROW(1,1); +-- error 1239 +select count(*) from t1 order by ROW(1,1); +#TODO remove comments after parser fixing +#-- error 1239 +#select count(*) from t1 order by i having (1,1); +#-- error 1239 +#select 1 from t1 limit (1,1), (1,1); +drop table t1; diff --git a/mysql-test/t/row_test.test b/mysql-test/t/row_test.test deleted file mode 100644 index 5daacaa1ee6..00000000000 --- a/mysql-test/t/row_test.test +++ /dev/null @@ -1,36 +0,0 @@ -SELECT ROW(1,2,3)=ROW(1,2,3); -SELECT ROW(2,2,3)=ROW(1+1,2,3); -SELECT ROW(1,2,3)=ROW(1+1,2,3); -SELECT ROW(1,2,3)<ROW(1+1,2,3); -SELECT ROW(1,2,3)>ROW(1+1,2,3); -SELECT ROW(1,2,3)<=ROW(1+1,2,3); -SELECT ROW(1,2,3)>=ROW(1+1,2,3); -SELECT ROW(1,2,3)<>ROW(1+1,2,3); -SELECT ROW(NULL,2,3)=ROW(NULL,2,3); -SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); -SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); -SELECT ROW('test',2,3.33)=ROW('test',2,3.33); --- error 1239 -SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); -drop table if exists t1; -create table t1 ( a int, b int, c int); -insert into t1 values (1,2,3), (2,3,1), (3,2,1); -select * from t1 where ROW(1,2,3)=ROW(a,b,c); -select * from t1 where ROW(0,2,3)=ROW(a,b,c); -select * from t1 where ROW(1,2,3)<ROW(a,b,c); -drop table t1; - --- error 1239 -select ROW(1,1); -drop table if exists t1; -create table t1 (i int); --- error 1239 -select 1 from t1 where ROW(1,1); --- error 1239 -select count(*) from t1 order by ROW(1,1); -#TODO remove comments after parser fixing -#-- error 1239 -#select count(*) from t1 order by i having (1,1); -#-- error 1239 -#select 1 from t1 limit (1,1), (1,1); -drop table t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 95bcabb17b4..38c137ef8e3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -144,7 +144,14 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) } if ((comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) for (uint i=0; i < n; i++) + { + if ((*a)->el(i)->cols() != (*b)->el(i)->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), (*a)->el(i)->cols()); + return 1; + } comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + } else { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); @@ -1047,6 +1054,11 @@ static int cmp_double(double *a,double *b) return *a < *b ? -1 : *a == *b ? 0 : 1; } +static int cmp_row(cmp_item_row* a, cmp_item_row* b) +{ + return a->compare(b); +} + int in_vector::find(Item *item) { byte *result=get_value(item); @@ -1069,7 +1081,6 @@ int in_vector::find(Item *item) return (int) ((*compare)(base+start*size,result) == 0); } - in_string::in_string(uint elements,qsort_cmp cmp_func) :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff),default_charset_info) {} @@ -1096,6 +1107,29 @@ byte *in_string::get_value(Item *item) return (byte*) item->val_str(&tmp); } +in_row::in_row(uint elements, Item * item) +{ + DBUG_ENTER("in_row::in_row"); + base= (char*) new cmp_item_row[elements]; + size= sizeof(cmp_item_row); + compare= (qsort_cmp) cmp_row; + tmp.store_value(item); + DBUG_VOID_RETURN; +} + +byte *in_row::get_value(Item *item) +{ + tmp.store_value(item); + return (byte *)&tmp; +} + +void in_row::set(uint pos, Item *item) +{ + DBUG_ENTER("in_row::set"); + DBUG_PRINT("enter", ("pos %u item 0x%lx", pos, (ulong) item)); + ((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item); + DBUG_VOID_RETURN; +} in_longlong::in_longlong(uint elements) :in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong) @@ -1108,13 +1142,12 @@ void in_longlong::set(uint pos,Item *item) byte *in_longlong::get_value(Item *item) { - tmp=item->val_int(); + tmp= item->val_int(); if (item->null_value) - return 0; /* purecov: inspected */ + return 0; return (byte*) &tmp; } - in_double::in_double(uint elements) :in_vector(elements,sizeof(double),(qsort_cmp) cmp_double) {} @@ -1126,12 +1159,146 @@ void in_double::set(uint pos,Item *item) byte *in_double::get_value(Item *item) { - tmp=item->val(); + tmp= item->val(); if (item->null_value) return 0; /* purecov: inspected */ return (byte*) &tmp; } +cmp_item* cmp_item::get_comparator (Item *item) +{ + switch (item->result_type()) { + case STRING_RESULT: + if (item->binary()) + return new cmp_item_binary_string; + else + return new cmp_item_sort_string; + break; + case INT_RESULT: + return new cmp_item_int; + break; + case REAL_RESULT: + return new cmp_item_real; + break; + case ROW_RESULT: + return new cmp_item_row; + break; + } + return 0; // to satisfy compiler :) +} + +cmp_item* cmp_item_sort_string::make_same() +{ + return new cmp_item_sort_string_in_static(); +} + +cmp_item* cmp_item_binary_string::make_same() +{ + return new cmp_item_binary_string_in_static(); +} + +cmp_item* cmp_item_int::make_same() +{ + return new cmp_item_int(); +} + +cmp_item* cmp_item_real::make_same() +{ + return new cmp_item_real(); +} + +cmp_item* cmp_item_row::make_same() +{ + return new cmp_item_row(); +} + +void cmp_item_row::store_value(Item *item) +{ + n= item->cols(); + if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n))) + { + item->null_value= 0; + for (uint i=0; i < n; i++) + if ((comparators[i]= cmp_item::get_comparator(item->el(i)))) + { + comparators[i]->store_value(item->el(i)); + item->null_value|= item->el(i)->null_value; + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } +} + +void cmp_item_row::store_value_by_template(cmp_item *t, Item *item) +{ + cmp_item_row *tmpl= (cmp_item_row*) t; + if (tmpl->n != item->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), tmpl->n); + return; + } + n= tmpl->n; + if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n))) + { + item->null_value= 0; + for (uint i=0; i < n; i++) + if ((comparators[i]= tmpl->comparators[i]->make_same())) + { + comparators[i]->store_value_by_template(tmpl->comparators[i], + item->el(i)); + item->null_value|= item->el(i)->null_value; + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } +} + +int cmp_item_row::cmp(Item *arg) +{ + arg->null_value= 0; + if (arg->cols() != n) + { + my_error(ER_CARDINALITY_COL, MYF(0), n); + return 1; + } + for(uint i=0; i < n; i++) + if(comparators[i]->cmp(arg->el(i))) + { + arg->null_value|= arg->el(i)->null_value; + return 1; + } + return 0; +} + +int cmp_item_row::compare(cmp_item *c) +{ + int res; + cmp_item_row *cmp= (cmp_item_row *) c; + for(uint i=0; i < n; i++) + if((res= comparators[i]->compare(cmp->comparators[i]))) + return res; + return 0; +} void Item_func_in::fix_length_and_dec() { @@ -1151,8 +1318,7 @@ void Item_func_in::fix_length_and_dec() array= new in_double(arg_count); break; case ROW_RESULT: - // This case should never be choosen - DBUG_ASSERT(0); + array= new in_row(arg_count, item); break; } uint j=0; @@ -1169,24 +1335,7 @@ void Item_func_in::fix_length_and_dec() } else { - switch (item->result_type()) { - case STRING_RESULT: - if (item->binary()) - in_item= new cmp_item_binary_string; - else - in_item= new cmp_item_sort_string; - break; - case INT_RESULT: - in_item= new cmp_item_int; - break; - case REAL_RESULT: - in_item= new cmp_item_real; - break; - case ROW_RESULT: - // This case should never be choosen - DBUG_ASSERT(0); - break; - } + in_item= cmp_item:: get_comparator(item); } maybe_null= item->maybe_null; max_length=2; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b69bc748388..c297019f977 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -17,6 +17,8 @@ /* compare and test functions */ +#include "assert.h" + #ifdef __GNUC__ #pragma interface /* gcc class implementation */ #endif @@ -38,16 +40,12 @@ public: Arg_comparator() {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {}; - inline void seta(Item **item) { a= item; } - inline void setb(Item **item) { b= item; } - int set_compare_func(Item_bool_func2 *owner, Item_result type); inline int set_compare_func(Item_bool_func2 *owner) { return set_compare_func(owner, item_cmp_type((*a)->result_type(), (*b)->result_type())); } - inline int set_cmp_func(Item_bool_func2 *owner, Item **a1, Item **a2, Item_result type) @@ -379,6 +377,7 @@ class in_vector :public Sql_alloc uint count; public: uint used_count; + in_vector() {} in_vector(uint elements,uint element_length,qsort_cmp cmp_func) :base((char*) sql_calloc(elements*element_length)), size(element_length), compare(cmp_func), count(elements), @@ -393,7 +392,6 @@ public: int find(Item *item); }; - class in_string :public in_vector { char buff[80]; @@ -405,7 +403,6 @@ public: byte *get_value(Item *item); }; - class in_longlong :public in_vector { longlong tmp; @@ -415,7 +412,6 @@ public: byte *get_value(Item *item); }; - class in_double :public in_vector { double tmp; @@ -425,7 +421,6 @@ public: byte *get_value(Item *item); }; - /* ** Classes for easy comparing of non const items */ @@ -435,74 +430,191 @@ class cmp_item :public Sql_alloc public: cmp_item() {} virtual ~cmp_item() {} - virtual void store_value(Item *item)=0; - virtual int cmp(Item *item)=0; + virtual void store_value(Item *item)= 0; + virtual int cmp(Item *item)= 0; + // for optimized IN with row + virtual int compare(cmp_item *item)= 0; + static cmp_item* get_comparator(Item *); + virtual cmp_item *make_same()= 0; + virtual void store_value_by_template(cmp_item *tmpl, Item *item) + { + store_value(item); + } }; +class cmp_item_string :public cmp_item +{ +protected: + String *value_res; +public: + friend class cmp_item_sort_string; + friend class cmp_item_binary_string; + friend class cmp_item_sort_string_in_static; + friend class cmp_item_binary_string_in_static; +}; -class cmp_item_sort_string :public cmp_item { - protected: +class cmp_item_sort_string :public cmp_item_string +{ +protected: char value_buff[80]; - String value,*value_res; + String value; public: - cmp_item_sort_string() :value(value_buff,sizeof(value_buff),default_charset_info) {} + cmp_item_sort_string(): + value(value_buff, sizeof(value_buff), default_charset_info) {} void store_value(Item *item) - { - value_res=item->val_str(&value); - } + { + value_res= item->val_str(&value); + } int cmp(Item *arg) - { - char buff[80]; - String tmp(buff,sizeof(buff),default_charset_info),*res; - if (!(res=arg->val_str(&tmp))) - return 1; /* Can't be right */ - return sortcmp(value_res,res); - } + { + char buff[80]; + String tmp(buff, sizeof(buff), default_charset_info), *res; + if (!(res= arg->val_str(&tmp))) + return 1; /* Can't be right */ + return sortcmp(value_res, res); + } + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return sortcmp(value_res, cmp->value_res); + } + cmp_item *make_same(); }; class cmp_item_binary_string :public cmp_item_sort_string { public: cmp_item_binary_string() {} int cmp(Item *arg) - { - char buff[80]; - String tmp(buff,sizeof(buff),default_charset_info),*res; - if (!(res=arg->val_str(&tmp))) - return 1; /* Can't be right */ - return stringcmp(value_res,res); - } + { + char buff[80]; + String tmp(buff,sizeof(buff),default_charset_info),*res; + if (!(res=arg->val_str(&tmp))) + return 1; /* Can't be right */ + return stringcmp(value_res,res); + } + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return stringcmp(value_res, cmp->value_res); + } + cmp_item *make_same(); }; - class cmp_item_int :public cmp_item { longlong value; public: void store_value(Item *item) - { - value=item->val_int(); - } + { + value= item->val_int(); + } int cmp(Item *arg) - { - return value != arg->val_int(); - } + { + return value != arg->val_int(); + } + int compare(cmp_item *c) + { + cmp_item_int *cmp= (cmp_item_int *)c; + return (value < cmp->value) ? -1 : ((value == cmp->value) ? 0 : 1); + } + cmp_item *make_same(); }; - class cmp_item_real :public cmp_item { double value; public: void store_value(Item *item) - { - value= item->val(); - } + { + value= item->val(); + } int cmp(Item *arg) - { - return value != arg->val(); - } + { + return value != arg->val(); + } + int compare(cmp_item *c) + { + cmp_item_real *cmp= (cmp_item_real *)c; + return (value < cmp->value)? -1 : ((value == cmp->value) ? 0 : 1); + } + cmp_item *make_same(); +}; + +class cmp_item_row :public cmp_item +{ + cmp_item **comparators; + uint n; +public: + cmp_item_row(): comparators(0), n(0) {} + ~cmp_item_row() + { + if(comparators) + for(uint i= 0; i < n; i++) + if (comparators[i]) + delete comparators[i]; + } + void store_value(Item *item); + int cmp(Item *arg); + int compare(cmp_item *arg); + cmp_item *make_same(); + void store_value_by_template(cmp_item *tmpl, Item *); +}; + + +class in_row :public in_vector +{ + cmp_item_row tmp; +public: + in_row(uint elements, Item *); + void set(uint pos,Item *item); + byte *get_value(Item *item); +}; + +/* + cmp_item for optimized IN with row (right part string, which never + be changed) +*/ + +class cmp_item_sort_string_in_static :public cmp_item_string +{ + protected: + String value; +public: + cmp_item_sort_string_in_static() {} + void store_value(Item *item) + { + value_res= item->val_str(&value); + } + int cmp(Item *item) + { + // Should never be called + DBUG_ASSERT(0); + return 1; + } + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return sortcmp(value_res, cmp->value_res); + } + cmp_item * make_same() + { + return new cmp_item_sort_string_in_static(); + } }; +class cmp_item_binary_string_in_static :public cmp_item_sort_string_in_static { +public: + cmp_item_binary_string_in_static() {} + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return stringcmp(value_res, cmp->value_res); + } + cmp_item * make_same() + { + return new cmp_item_binary_string_in_static(); + } +}; class Item_func_in :public Item_int_func { @@ -512,12 +624,15 @@ class Item_func_in :public Item_int_func bool have_null; public: Item_func_in(Item *a,List<Item> &list) - :Item_int_func(list), item(a), array(0), in_item(0), have_null(0) {} + :Item_int_func(list), item(a), array(0), in_item(0), have_null(0) + { + allowed_arg_cols= item->cols(); + } longlong val_int(); bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) { - bool res=(item->check_cols(1) || - item->fix_fields(thd, tlist, &item) || + // We do not check item->cols(), because allowed_arg_cols assigned from it + bool res=(item->fix_fields(thd, tlist, &item) || Item_func::fix_fields(thd, tlist, ref)); with_sum_func= with_sum_func || item->with_sum_func; return res; @@ -541,8 +656,6 @@ class Item_func_in :public Item_int_func } }; - - /* Functions used by where clause */ class Item_func_isnull :public Item_bool_func diff --git a/sql/item_row.cc b/sql/item_row.cc index 464a8fd0ec5..e073f8e24e7 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -18,8 +18,10 @@ #include "assert.h" Item_row::Item_row(List<Item> &arg): - Item(), array_holder(1) + Item(), array_holder(1), used_tables_cache(0), const_item_cache(1) { + + //TODO: think placing 2-3 component items in item (as it done for function) if ((arg_count= arg.elements)) items= (Item**) sql_alloc(sizeof(Item*)*arg_count); else @@ -45,16 +47,31 @@ void Item_row::illegal_method_call(const char *method) bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) { - tables= 0; + null_value= 0; + maybe_null= 0; for (uint i= 0; i < arg_count; i++) { if (items[i]->fix_fields(thd, tabl, items+i)) return 1; - tables |= items[i]->used_tables(); + used_tables_cache |= items[i]->used_tables(); + const_item_cache&= items[i]->const_item(); + maybe_null|= items[i]->maybe_null; } return 0; } +void Item_row::update_used_tables() +{ + used_tables_cache= 0; + const_item_cache= 1; + for (uint i= 0; i < arg_count; i++) + { + items[i]->update_used_tables(); + used_tables_cache|= items[i]->used_tables(); + const_item_cache&= items[i]->const_item(); + } +} + bool Item_row::check_cols(uint c) { if (c != arg_count) diff --git a/sql/item_row.h b/sql/item_row.h index 5580250b4fb..d097fca8f1d 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -17,13 +17,17 @@ class Item_row: public Item { bool array_holder; - table_map tables; + table_map used_tables_cache; + bool const_item_cache; uint arg_count; Item **items; public: Item_row(List<Item> &); Item_row(Item_row *item): - Item(), array_holder(0), tables(item->tables), arg_count(item->arg_count), + Item(), array_holder(0), + used_tables_cache(item->used_tables_cache), + const_item_cache(item->const_item_cache), + arg_count(item->arg_count), items(item->items) {} @@ -56,8 +60,10 @@ public: return 0; }; bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); - table_map used_tables() const { return tables; }; + table_map used_tables() const { return used_tables_cache; }; + bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } + void update_used_tables(); virtual uint cols() { return arg_count; } virtual Item* el(uint i) { return items[i]; } diff --git a/sql/sql_list.h b/sql/sql_list.h index 56e6528f214..1711a340cae 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -25,8 +25,16 @@ class Sql_alloc { public: - static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { + return (void*) sql_alloc((uint) size); + } + static void *operator new[](size_t size) + { + return (void*) sql_alloc((uint) size); + } static void operator delete(void *ptr, size_t size) {} /*lint -e715 */ + static void operator delete[](void *ptr, size_t size) {} #ifdef HAVE_purify bool dummy; inline Sql_alloc() :dummy(0) {} diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5b8e2085982..8e3288dc23b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -791,6 +791,16 @@ JOIN::exec() HA_POS_ERROR))) DBUG_VOID_RETURN; + /* + We don't have to store rows in temp table that doesn't match HAVING if: + - we are sorting the table and writing complete group rows to the + temp table. + - We are using DISTINCT without resolving the distinct as a GROUP BY + on all columns. + + If having is not handled here, it will be checked before the row + is sent to the client. + */ if (having_list && (sort_and_group || (exec_tmp_table->distinct && !group_list))) having=having_list; |