summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <bell@sanja.is.com.ua>2002-06-19 17:52:44 +0300
committerunknown <bell@sanja.is.com.ua>2002-06-19 17:52:44 +0300
commitc6a2ae17a01d1f93257ea1ce5af0513d870585b0 (patch)
treecc55f99d5599771fbb2ddecda5ce0467fd2ede67
parent454712d20e89b34e2c45973f3d601f4720c3e471 (diff)
downloadmariadb-git-c6a2ae17a01d1f93257ea1ce5af0513d870585b0.tar.gz
EXISTS type of subselect
more correct parameters in result creation script mysql-test/create-test-result: more correct parameters in result creation script mysql-test/r/subselect.result: test of EXISTS mysql-test/t/subselect.test: test of EXISTS sql/item_subselect.cc: EXISTS type of subselect sql/item_subselect.h: EXISTS type of subselect sql/sql_class.cc: EXISTS type of subselect sql/sql_class.h: EXISTS type of subselect sql/sql_yacc.yy: EXISTS type of subselect
-rwxr-xr-xmysql-test/create-test-result2
-rw-r--r--mysql-test/r/subselect.result7
-rw-r--r--mysql-test/t/subselect.test2
-rw-r--r--sql/item_subselect.cc121
-rw-r--r--sql/item_subselect.h89
-rw-r--r--sql/sql_class.cc43
-rw-r--r--sql/sql_class.h23
-rw-r--r--sql/sql_yacc.yy27
8 files changed, 235 insertions, 79 deletions
diff --git a/mysql-test/create-test-result b/mysql-test/create-test-result
index bfd64f32fc5..a50b4c87641 100755
--- a/mysql-test/create-test-result
+++ b/mysql-test/create-test-result
@@ -32,7 +32,7 @@ result_file=$RESULT_DIR/$test_name.result
touch $result_file
echo "Running the test case against empty file, will fail, but don't worry"
-./mysql-test-run --do-test=$test_name
+./mysql-test-run --local $test_name
reject_file=$result_file.reject
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 2e40d0a92d8..37a66993ef2 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -67,4 +67,11 @@ b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)
8 7.5000
8 6.0000
9 5.5000
+select * from t3 where exists (select * from t2 where t2.b=t3.a);
+a
+7
+select * from t3 where not exists (select * from t2 where t2.b=t3.a);
+a
+6
+3
drop table t1,t2,t3,t4;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index c94522fde8f..78300dc3e09 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -26,4 +26,6 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from
select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1);
select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1);
select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4;
+select * from t3 where exists (select * from t2 where t2.b=t3.a);
+select * from t3 where not exists (select * from t2 where t2.b=t3.a);
drop table t1,t2,t3,t4;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index c2349ed414c..d8f9cf40d50 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -35,12 +35,13 @@ SUBSELECT TODO:
#include "mysql_priv.h"
#include "sql_select.h"
-Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex):
+Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex,
+ select_subselect *result):
assigned(0), executed(0), optimized(0), error(0)
{
DBUG_ENTER("Item_subselect::Item_subselect");
DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
- result= new select_subselect(this);
+ this->result= result;
SELECT_LEX_UNIT *unit= select_lex->master_unit();
unit->offset_limit_cnt= unit->global_parameters->offset_limit;
unit->select_limit_cnt= unit->global_parameters->select_limit+
@@ -51,41 +52,15 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex):
select_lex->options&= ~OPTION_FOUND_ROWS;
join= new JOIN(thd, select_lex->item_list, select_lex->options, result);
this->select_lex= select_lex;
- maybe_null= 1;
+ assign_null();
/*
item value is NULL if select_subselect not changed this value
(i.e. some rows will be found returned)
*/
- assign_null();
+ null_value= 1;
DBUG_VOID_RETURN;
}
-Item::Type Item_subselect::type() const
-{
- return SUBSELECT_ITEM;
-}
-
-double Item_subselect::val ()
-{
- if (exec())
- return 0;
- return real_value;
-}
-
-longlong Item_subselect::val_int ()
-{
- if (exec())
- return 0;
- return int_value;
-}
-
-String *Item_subselect::val_str (String *str)
-{
- if (exec() || null_value)
- return 0;
- return &str_value;
-}
-
void Item_subselect::make_field (Send_field *tmp_field)
{
if (null_value)
@@ -108,9 +83,9 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
//TODO: subselects in having do not suported now
my_printf_error(ER_SYNTAX_ERROR, ER(ER_SYNTAX_ERROR), MYF(0));
return 1;
- }
+ }
// Is it one field subselect?
- if (select_lex->item_list.elements != 1)
+ if (select_lex->item_list.elements > max_columns)
{
my_printf_error(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0));
return 1;
@@ -131,13 +106,14 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
int Item_subselect::exec()
{
+ DBUG_ENTER("Item_subselect::exec");
if (!optimized)
{
optimized=1;
if (join->optimize())
{
executed= 1;
- return (join->error?join->error:1);
+ DBUG_RETURN(join->error?join->error:1);
}
}
if (join->select_lex->depended && executed)
@@ -145,7 +121,7 @@ int Item_subselect::exec()
if (join->reinit())
{
error= 1;
- return 1;
+ DBUG_RETURN(1);
}
assign_null();
executed= assigned= 0;
@@ -157,7 +133,80 @@ int Item_subselect::exec()
join->exec();
join->thd->lex.select= save_select;
executed= 1;
- return join->error;
+ DBUG_RETURN(join->error);
}
- return 0;
+ DBUG_RETURN(0);
}
+
+inline table_map Item_subselect::used_tables() const
+{
+ return (table_map) select_lex->depended ? 1L : 0L;
+}
+
+Item_singleval_subselect::Item_singleval_subselect(THD *thd,
+ st_select_lex *select_lex):
+ Item_subselect(thd, select_lex, new select_singleval_subselect(this))
+{
+ max_columns= 1;
+ maybe_null= 1;
+}
+
+Item::Type Item_subselect::type() const
+{
+ return SUBSELECT_ITEM;
+}
+
+double Item_singleval_subselect::val ()
+{
+ if (exec())
+ return 0;
+ return real_value;
+}
+
+longlong Item_singleval_subselect::val_int ()
+{
+ if (exec())
+ return 0;
+ return int_value;
+}
+
+String *Item_singleval_subselect::val_str (String *str)
+{
+ if (exec() || null_value)
+ return 0;
+ return &str_value;
+}
+
+Item_exists_subselect::Item_exists_subselect(THD *thd,
+ st_select_lex *select_lex):
+ Item_subselect(thd, select_lex, new select_singleval_subselect(this))
+{
+ max_columns= UINT_MAX;
+ null_value= 0; //can't be NULL
+ maybe_null= 0; //can't be NULL
+ value= 0;
+ select_lex->select_limit= 1; // we need only 1 row to determinate existence
+}
+
+double Item_exists_subselect::val ()
+{
+ if (exec())
+ return 0;
+ return (double) value;
+}
+
+longlong Item_exists_subselect::val_int ()
+{
+ if (exec())
+ return 0;
+ return value;
+}
+
+String *Item_exists_subselect::val_str(String *str)
+{
+ if (exec())
+ return 0;
+ str->set(value);
+ return str;
+}
+
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index c6963df2d53..79832116c67 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -24,42 +24,34 @@ struct st_select_lex;
class JOIN;
class select_subselect;
-/* simple (not depended of covered select ) subselect */
+/* base class for subselects */
class Item_subselect :public Item
{
protected:
- longlong int_value;
- double real_value;
+ uint max_columns;
my_bool assigned; /* value already assigned to subselect */
my_bool executed; /* simple subselect is executed */
my_bool optimized; /* simple subselect is optimized */
my_bool error; /* error in query */
- enum Item_result res_type;
int exec();
- void assign_null()
+ virtual void assign_null()
{
null_value= 1;
- int_value= 0;
- real_value= 0;
- max_length= 4;
- res_type= STRING_RESULT;
}
public:
st_select_lex *select_lex;
JOIN *join;
select_subselect *result;
- Item_subselect(THD *thd, st_select_lex *select_lex);
+ Item_subselect(THD *thd, st_select_lex *select_lex,
+ select_subselect* result);
Item_subselect(Item_subselect *item)
{
null_value= item->null_value;
- int_value= item->int_value;
- real_value= item->real_value;
- max_length= item->max_length;
decimals= item->decimals;
- res_type= item->res_type;
+ max_columns= item->max_columns;
assigned= item->assigned;
executed= item->executed;
select_lex= item->select_lex;
@@ -69,16 +61,75 @@ public:
error= item->error;
}
enum Type type() const;
- double val ();
- longlong val_int ();
- String *val_str (String *);
bool is_null() { return null_value; }
void make_field (Send_field *);
bool fix_fields(THD *thd, TABLE_LIST *tables);
- Item *new_item() { return new Item_subselect(this); }
- enum Item_result result_type() const { return res_type; }
+ table_map used_tables() const;
friend class select_subselect;
};
+/* single value subselect */
+
+class Item_singleval_subselect :public Item_subselect
+{
+protected:
+ longlong int_value;
+ double real_value;
+ enum Item_result res_type;
+
+ virtual void assign_null()
+ {
+ null_value= 1;
+ int_value= 0;
+ real_value= 0;
+ max_length= 4;
+ res_type= STRING_RESULT;
+ }
+public:
+ Item_singleval_subselect(THD *thd, st_select_lex *select_lex);
+ Item_singleval_subselect(Item_singleval_subselect *item):
+ Item_subselect(item)
+ {
+ int_value= item->int_value;
+ real_value= item->real_value;
+ max_length= item->max_length;
+ decimals= item->decimals;
+ res_type= item->res_type;
+ }
+ double val ();
+ longlong val_int ();
+ String *val_str (String *);
+ Item *new_item() { return new Item_singleval_subselect(this); }
+ enum Item_result result_type() const { return res_type; }
+
+ friend class select_singleval_subselect;
+};
+
+/* exists subselect */
+
+class Item_exists_subselect :public Item_subselect
+{
+protected:
+ longlong value;
+
+ virtual void assign_null()
+ {
+ value= 0;
+ }
+public:
+ Item_exists_subselect(THD *thd, st_select_lex *select_lex);
+ Item_exists_subselect(Item_exists_subselect *item):
+ Item_subselect(item)
+ {
+ value= item->value;
+ }
+ Item *new_item() { return new Item_exists_subselect(this); }
+ enum Item_result result_type() const { return INT_RESULT;}
+ longlong val_int();
+ double val();
+ String *val_str(String*);
+
+ friend class select_exists_subselect;
+};
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 86e4e6896e6..85f5b3cb5f2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -763,7 +763,6 @@ void select_dump::send_error(uint errcode,const char *err)
file= -1;
}
-
bool select_dump::send_eof()
{
int error=test(end_io_cache(&cache));
@@ -782,10 +781,11 @@ select_subselect::select_subselect(Item_subselect *item)
this->item=item;
}
-bool select_subselect::send_data(List<Item> &items)
+bool select_singleval_subselect::send_data(List<Item> &items)
{
- DBUG_ENTER("select_subselect::send_data");
- if (item->assigned){
+ DBUG_ENTER("select_singleval_subselect::send_data");
+ Item_singleval_subselect *it= (Item_singleval_subselect *)item;
+ if (it->assigned){
my_printf_error(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
DBUG_RETURN(1);
}
@@ -800,18 +800,33 @@ bool select_subselect::send_data(List<Item> &items)
Following val() call have to be first, because function AVG() & STD()
calculate value on it & determinate "is it NULL?".
*/
- item->real_value= val_item->val();
- if ((item->null_value= val_item->is_null()))
+ it->real_value= val_item->val();
+ if ((it->null_value= val_item->is_null()))
{
- item->assign_null();
+ it->assign_null();
} else {
- item->max_length= val_item->max_length;
- item->decimals= val_item->decimals;
- item->binary= val_item->binary;
- val_item->val_str(&item->str_value);
- item->int_value= val_item->val_int();
- item->res_type= val_item->result_type();
+ it->max_length= val_item->max_length;
+ it->decimals= val_item->decimals;
+ it->binary= val_item->binary;
+ val_item->val_str(&it->str_value);
+ it->int_value= val_item->val_int();
+ it->res_type= val_item->result_type();
}
- item->assigned= 1;
+ it->assigned= 1;
DBUG_RETURN(0);
}
+
+bool select_exists_subselect::send_data(List<Item> &items)
+{
+ DBUG_ENTER("select_exists_subselect::send_data");
+ Item_exists_subselect *it= (Item_exists_subselect *)item;
+ if (unit->offset_limit_cnt)
+ { // Using limit offset,count
+ unit->offset_limit_cnt--;
+ DBUG_RETURN(0);
+ }
+ it->value= 1;
+ it->assigned= 1;
+ DBUG_RETURN(0);
+}
+
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8a1a299ceee..eb57b5828f6 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -712,19 +712,36 @@ class select_union :public select_result {
bool flush();
};
-/* Single value subselect interface class */
+/* Base subselect interface class */
class select_subselect :public select_result
{
+protected:
Item_subselect *item;
public:
select_subselect(Item_subselect *item);
bool send_fields(List<Item> &list, uint flag) { return 0; };
- bool send_data(List<Item> &items);
+ bool send_data(List<Item> &items)=0;
bool send_eof() { return 0; };
-
+
friend class Ttem_subselect;
};
+/* Single value subselect interface class */
+class select_singleval_subselect :public select_subselect
+{
+public:
+ select_singleval_subselect(Item_subselect *item):select_subselect(item){}
+ bool send_data(List<Item> &items);
+};
+
+/* EXISTS subselect interface class */
+class select_exists_subselect :public select_subselect
+{
+public:
+ select_exists_subselect(Item_subselect *item):select_subselect(item){}
+ bool send_data(List<Item> &items);
+};
+
/* Structs used when sorting */
typedef struct st_sort_field {
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index efc8b8b5389..9047bc472ac 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -548,7 +548,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
- using_list subselect subselect_init
+ using_list singleval_subselect singleval_subselect_init
+ exists_subselect exists_subselect_init
%type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg
@@ -1738,7 +1739,8 @@ simple_expr:
| NOT expr %prec NEG { $$= new Item_func_not($2); }
| '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; }
- | subselect { $$= $1; }
+ | EXISTS exists_subselect { $$= $2; }
+ | singleval_subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' expr ')'
{ Select->ftfunc_list.push_back((Item_func_match *)
@@ -3918,17 +3920,30 @@ union_option:
/* empty */ {}
| ALL {Lex->union_option=1;};
-subselect:
- subselect_start subselect_init
+singleval_subselect:
+ subselect_start singleval_subselect_init
subselect_end
{
$$= $2;
};
-subselect_init:
+singleval_subselect_init:
select_init
{
- $$= new Item_subselect(current_thd, Lex->select);
+ $$= new Item_singleval_subselect(current_thd, Lex->select);
+ };
+
+exists_subselect:
+ subselect_start exists_subselect_init
+ subselect_end
+ {
+ $$= $2;
+ };
+
+exists_subselect_init:
+ select_init
+ {
+ $$= new Item_exists_subselect(current_thd, Lex->select);
};
subselect_start: