Loading sql/item_subselect.cc +30 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,10 @@ Item_subselect::Item_subselect(): void Item_subselect::init(st_select_lex *select_lex, select_subselect *result) { /* Please see Item_singlerow_subselect::invalidate_and_restore_select_lex(), which depends on alterations to the parse tree implemented here. */ DBUG_ENTER("Item_subselect::init"); DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex)); Loading Loading @@ -91,6 +95,12 @@ void Item_subselect::init(st_select_lex *select_lex, DBUG_VOID_RETURN; } st_select_lex * Item_subselect::get_select_lex() { return unit->first_select(); } void Item_subselect::cleanup() { DBUG_ENTER("Item_subselect::cleanup"); Loading Loading @@ -307,6 +317,26 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) DBUG_VOID_RETURN; } st_select_lex * Item_singlerow_subselect::invalidate_and_restore_select_lex() { DBUG_ENTER("Item_singlerow_subselect::invalidate_and_restore_select_lex"); st_select_lex *result= get_select_lex(); DBUG_ASSERT(result); /* This code restore the parse tree in it's state before the execution of Item_singlerow_subselect::Item_singlerow_subselect(), and in particular decouples this object from the SELECT_LEX, so that the SELECT_LEX can be used with a different flavor or Item_subselect instead, as part of query rewriting. */ unit->item= NULL; DBUG_RETURN(result); } Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param, Item_subselect *parent, st_select_lex *select_lex, Loading sql/item_subselect.h +16 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,12 @@ class Item_subselect :public Item_result_field enum_parsing_place place() { return parsing_place; } bool walk(Item_processor processor, bool walk_subquery, byte *arg); /** Get the SELECT_LEX structure associated with this Item. @return the SELECT_LEX structure associated with this Item */ st_select_lex* get_select_lex(); friend class select_subselect; friend class Item_in_optimizer; friend bool Item_field::fix_fields(THD *, Item **); Loading Loading @@ -169,6 +175,16 @@ class Item_singlerow_subselect :public Item_subselect bool null_inside(); void bring_value(); /** This method is used to implement a special case of semantic tree rewriting, mandated by a SQL:2003 exception in the specification. The only caller of this method is handle_sql2003_note184_exception(), see the code there for more details. Do not call this method for other purposes. @return the SELECT_LEX structure that was given in the constructor. */ st_select_lex* invalidate_and_restore_select_lex(); friend class select_singlerow_subselect; }; Loading sql/sql_yacc.yy +98 −17 Original line number Diff line number Diff line Loading @@ -310,6 +310,81 @@ void case_stmt_action_end_case(LEX *lex, bool simple) lex->sphead->do_cont_backpatch(); } /** Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>. See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383. This function returns the proper item for the SQL expression <code>left [NOT] IN ( expr )</code> @param thd the current thread @param left the in predicand @param equal true for IN predicates, false for NOT IN predicates @param expr first and only expression of the in value list @return an expression representing the IN predicate. */ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, Item *expr) { /* Relevant references for this issue: - SQL:2003, Part 2, section 8.4 <in predicate>, page 383, - SQL:2003, Part 2, section 7.2 <row value expression>, page 296, - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174, - SQL:2003, Part 2, section 7.15 <subquery>, page 370, - SQL:2003 Feature F561, "Full value expressions". The exception in SQL:2003 Note 184 means: Item_singlerow_subselect, which corresponds to a <scalar subquery>, should be re-interpreted as an Item_in_subselect, which corresponds to a <table subquery> when used inside an <in predicate>. Our reading of Note 184 is reccursive, so that all: - IN (( <subquery> )) - IN ((( <subquery> ))) - IN '('^N <subquery> ')'^N - etc should be interpreted as a <table subquery>, no matter how deep in the expression the <subquery> is. */ Item *result; DBUG_ENTER("handle_sql2003_note184_exception"); if (expr->type() == Item::SUBSELECT_ITEM) { Item_subselect *expr2 = (Item_subselect*) expr; if (expr2->substype() == Item_subselect::SINGLEROW_SUBS) { Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2; st_select_lex *subselect; /* Implement the mandated change, by altering the semantic tree: left IN Item_singlerow_subselect(subselect) is modified to left IN (subselect) which is represented as Item_in_subselect(left, subselect) */ subselect= expr3->invalidate_and_restore_select_lex(); result= new (thd->mem_root) Item_in_subselect(left, subselect); if (! equal) result = negate_expression(thd, result); DBUG_RETURN(result); } } if (equal) result= new (thd->mem_root) Item_func_eq(left, expr); else result= new (thd->mem_root) Item_func_ne(left, expr); DBUG_RETURN(result); } %} %union { int num; Loading Loading @@ -6169,28 +6244,34 @@ bool_pri: predicate: bit_expr IN_SYM '(' subselect ')' { $$= new Item_in_subselect($1, $4); } { $$= new (YYTHD->mem_root) Item_in_subselect($1, $4); } | bit_expr not IN_SYM '(' subselect ')' { $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); } { THD *thd= YYTHD; Item *item= new (thd->mem_root) Item_in_subselect($1, $5); $$= negate_expression(thd, item); } | bit_expr IN_SYM '(' expr ')' { $$= new Item_func_eq($1, $4); $$= handle_sql2003_note184_exception(YYTHD, $1, true, $4); } | bit_expr IN_SYM '(' expr ',' expr_list ')' { $6->push_front($4); $6->push_front($1); $$= new Item_func_in(*$6); $$= new (YYTHD->mem_root) Item_func_in(*$6); } | bit_expr not IN_SYM '(' expr ')' { $$= new Item_func_ne($1, $5); $$= handle_sql2003_note184_exception(YYTHD, $1, false, $5); } | bit_expr not IN_SYM '(' expr ',' expr_list ')' { $7->push_front($5); $7->push_front($1); Item_func_in *item = new Item_func_in(*$7); Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7); item->negate(); $$= item; } Loading Loading
sql/item_subselect.cc +30 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,10 @@ Item_subselect::Item_subselect(): void Item_subselect::init(st_select_lex *select_lex, select_subselect *result) { /* Please see Item_singlerow_subselect::invalidate_and_restore_select_lex(), which depends on alterations to the parse tree implemented here. */ DBUG_ENTER("Item_subselect::init"); DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex)); Loading Loading @@ -91,6 +95,12 @@ void Item_subselect::init(st_select_lex *select_lex, DBUG_VOID_RETURN; } st_select_lex * Item_subselect::get_select_lex() { return unit->first_select(); } void Item_subselect::cleanup() { DBUG_ENTER("Item_subselect::cleanup"); Loading Loading @@ -307,6 +317,26 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) DBUG_VOID_RETURN; } st_select_lex * Item_singlerow_subselect::invalidate_and_restore_select_lex() { DBUG_ENTER("Item_singlerow_subselect::invalidate_and_restore_select_lex"); st_select_lex *result= get_select_lex(); DBUG_ASSERT(result); /* This code restore the parse tree in it's state before the execution of Item_singlerow_subselect::Item_singlerow_subselect(), and in particular decouples this object from the SELECT_LEX, so that the SELECT_LEX can be used with a different flavor or Item_subselect instead, as part of query rewriting. */ unit->item= NULL; DBUG_RETURN(result); } Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param, Item_subselect *parent, st_select_lex *select_lex, Loading
sql/item_subselect.h +16 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,12 @@ class Item_subselect :public Item_result_field enum_parsing_place place() { return parsing_place; } bool walk(Item_processor processor, bool walk_subquery, byte *arg); /** Get the SELECT_LEX structure associated with this Item. @return the SELECT_LEX structure associated with this Item */ st_select_lex* get_select_lex(); friend class select_subselect; friend class Item_in_optimizer; friend bool Item_field::fix_fields(THD *, Item **); Loading Loading @@ -169,6 +175,16 @@ class Item_singlerow_subselect :public Item_subselect bool null_inside(); void bring_value(); /** This method is used to implement a special case of semantic tree rewriting, mandated by a SQL:2003 exception in the specification. The only caller of this method is handle_sql2003_note184_exception(), see the code there for more details. Do not call this method for other purposes. @return the SELECT_LEX structure that was given in the constructor. */ st_select_lex* invalidate_and_restore_select_lex(); friend class select_singlerow_subselect; }; Loading
sql/sql_yacc.yy +98 −17 Original line number Diff line number Diff line Loading @@ -310,6 +310,81 @@ void case_stmt_action_end_case(LEX *lex, bool simple) lex->sphead->do_cont_backpatch(); } /** Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>. See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383. This function returns the proper item for the SQL expression <code>left [NOT] IN ( expr )</code> @param thd the current thread @param left the in predicand @param equal true for IN predicates, false for NOT IN predicates @param expr first and only expression of the in value list @return an expression representing the IN predicate. */ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, Item *expr) { /* Relevant references for this issue: - SQL:2003, Part 2, section 8.4 <in predicate>, page 383, - SQL:2003, Part 2, section 7.2 <row value expression>, page 296, - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174, - SQL:2003, Part 2, section 7.15 <subquery>, page 370, - SQL:2003 Feature F561, "Full value expressions". The exception in SQL:2003 Note 184 means: Item_singlerow_subselect, which corresponds to a <scalar subquery>, should be re-interpreted as an Item_in_subselect, which corresponds to a <table subquery> when used inside an <in predicate>. Our reading of Note 184 is reccursive, so that all: - IN (( <subquery> )) - IN ((( <subquery> ))) - IN '('^N <subquery> ')'^N - etc should be interpreted as a <table subquery>, no matter how deep in the expression the <subquery> is. */ Item *result; DBUG_ENTER("handle_sql2003_note184_exception"); if (expr->type() == Item::SUBSELECT_ITEM) { Item_subselect *expr2 = (Item_subselect*) expr; if (expr2->substype() == Item_subselect::SINGLEROW_SUBS) { Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2; st_select_lex *subselect; /* Implement the mandated change, by altering the semantic tree: left IN Item_singlerow_subselect(subselect) is modified to left IN (subselect) which is represented as Item_in_subselect(left, subselect) */ subselect= expr3->invalidate_and_restore_select_lex(); result= new (thd->mem_root) Item_in_subselect(left, subselect); if (! equal) result = negate_expression(thd, result); DBUG_RETURN(result); } } if (equal) result= new (thd->mem_root) Item_func_eq(left, expr); else result= new (thd->mem_root) Item_func_ne(left, expr); DBUG_RETURN(result); } %} %union { int num; Loading Loading @@ -6169,28 +6244,34 @@ bool_pri: predicate: bit_expr IN_SYM '(' subselect ')' { $$= new Item_in_subselect($1, $4); } { $$= new (YYTHD->mem_root) Item_in_subselect($1, $4); } | bit_expr not IN_SYM '(' subselect ')' { $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); } { THD *thd= YYTHD; Item *item= new (thd->mem_root) Item_in_subselect($1, $5); $$= negate_expression(thd, item); } | bit_expr IN_SYM '(' expr ')' { $$= new Item_func_eq($1, $4); $$= handle_sql2003_note184_exception(YYTHD, $1, true, $4); } | bit_expr IN_SYM '(' expr ',' expr_list ')' { $6->push_front($4); $6->push_front($1); $$= new Item_func_in(*$6); $$= new (YYTHD->mem_root) Item_func_in(*$6); } | bit_expr not IN_SYM '(' expr ')' { $$= new Item_func_ne($1, $5); $$= handle_sql2003_note184_exception(YYTHD, $1, false, $5); } | bit_expr not IN_SYM '(' expr ',' expr_list ')' { $7->push_front($5); $7->push_front($1); Item_func_in *item = new Item_func_in(*$7); Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7); item->negate(); $$= item; } Loading