diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2019-07-26 07:03:39 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2019-07-26 07:03:39 +0200 |
commit | cf8c2a3c3b2eb05df419ce014b98a71b1e75ad6b (patch) | |
tree | 0e9c8d48fda7b7494b5d3b220bc6af64e4f3e64a /sql | |
parent | fc77a66c7eb1b8e90753814aa567daeaabd0dd90 (diff) | |
parent | 584d213235704113cf0d70319c0521d93b8744c6 (diff) | |
download | mariadb-git-cf8c2a3c3b2eb05df419ce014b98a71b1e75ad6b.tar.gz |
Merge branch '10.1' into 10.2
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 13 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_func.cc | 1 | ||||
-rw-r--r-- | sql/item_subselect.cc | 27 | ||||
-rw-r--r-- | sql/item_xmlfunc.cc | 4 | ||||
-rw-r--r-- | sql/item_xmlfunc.h | 3 | ||||
-rw-r--r-- | sql/sql_acl.cc | 1 | ||||
-rw-r--r-- | sql/sql_delete.cc | 3 | ||||
-rw-r--r-- | sql/sql_insert.cc | 6 | ||||
-rw-r--r-- | sql/sql_lex.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.h | 25 | ||||
-rw-r--r-- | sql/sql_parse.cc | 235 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 7 | ||||
-rw-r--r-- | sql/sql_select.cc | 9 | ||||
-rw-r--r-- | sql/sql_table.cc | 5 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 35 | ||||
-rw-r--r-- | sql/table.h | 24 |
17 files changed, 348 insertions, 56 deletions
diff --git a/sql/item.cc b/sql/item.cc index da4a3ee1e05..efedc1ec8d1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10697,11 +10697,14 @@ table_map Item_direct_view_ref::used_tables() const table_map Item_direct_view_ref::not_null_tables() const { - return get_depended_from() ? - 0 : - ((view->is_merged_derived() || view->merged || !view->table) ? - (*ref)->not_null_tables() : - view->table->map); + if (get_depended_from()) + return 0; + if (!( view->merged || !view->table)) + return view->table->map; + TABLE *tab= get_null_ref_table(); + if (tab == NO_NULL_TABLE || (*ref)->used_tables()) + return (*ref)->not_null_tables(); + return get_null_ref_table()->map; } /* diff --git a/sql/item.h b/sql/item.h index 326b1a0f867..49762d3326f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4832,6 +4832,7 @@ public: void update_used_tables(); table_map not_null_tables() const; bool const_item() const { return used_tables() == 0; } + TABLE *get_null_ref_table() const { return null_ref_table; } bool walk(Item_processor processor, bool walk_subquery, void *arg) { return (*ref)->walk(processor, walk_subquery, arg) || diff --git a/sql/item_func.cc b/sql/item_func.cc index 6b3373f0795..5ff1b26d734 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -222,6 +222,7 @@ Item_func::fix_fields(THD *thd, Item **ref) with_window_func= with_window_func || item->with_window_func; with_field= with_field || item->with_field; used_tables_and_const_cache_join(item); + not_null_tables_cache|= item->not_null_tables(); with_subselect|= item->has_subquery(); } } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6140097891b..2e023658baf 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1518,16 +1518,23 @@ bool Item_exists_subselect::fix_length_and_dec() { DBUG_ENTER("Item_exists_subselect::fix_length_and_dec"); init_length_and_dec(); - /* - We need only 1 row to determine existence (i.e. any EXISTS that is not - an IN always requires LIMIT 1) - */ - Item *item= new (thd->mem_root) Item_int(thd, (int32) 1); - if (!item) - DBUG_RETURN(TRUE); - thd->change_item_tree(&unit->global_parameters()->select_limit, - item); - DBUG_PRINT("info", ("Set limit to 1")); + // If limit is not set or it is constant more than 1 + if (!unit->global_parameters()->select_limit || + (unit->global_parameters()->select_limit->basic_const_item() && + unit->global_parameters()->select_limit->val_int() > 1)) + { + /* + We need only 1 row to determine existence (i.e. any EXISTS that is not + an IN always requires LIMIT 1) + */ + Item *item= new (thd->mem_root) Item_int(thd, (int32) 1); + if (!item) + DBUG_RETURN(TRUE); + thd->change_item_tree(&unit->global_parameters()->select_limit, + item); + unit->global_parameters()->explicit_limit= 1; // we set the limit + DBUG_PRINT("info", ("Set limit to 1")); + } DBUG_RETURN(FALSE); } diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 7fa9f6a8c22..0e62e29bfe2 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2005, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2017, MariaDB +/* Copyright (c) 2005, 2019, Oracle and/or its affiliates. + Copyright (c) 2009, 2019, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/item_xmlfunc.h b/sql/item_xmlfunc.h index 692b7a4249e..e00f071fc0c 100644 --- a/sql/item_xmlfunc.h +++ b/sql/item_xmlfunc.h @@ -1,8 +1,7 @@ #ifndef ITEM_XMLFUNC_INCLUDED #define ITEM_XMLFUNC_INCLUDED -/* Copyright (c) 2000-2007 MySQL AB, 2009 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 6d339b81ce2..eb84368bf9f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -12282,6 +12282,7 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio, ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin; DBUG_EXECUTE_IF("auth_disconnect", { DBUG_RETURN(1); }); + DBUG_EXECUTE_IF("auth_invalid_plugin", client_auth_plugin="foo/bar"; ); DBUG_ASSERT(client_auth_plugin); /* diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b8e158d39c3..e2d4cd47580 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2010, Oracle and/or its affiliates. + Copyright (c) 2000, 2019, Oracle and/or its affiliates. Copyright (c) 2010, 2019, MariaDB This program is free software; you can redistribute it and/or modify @@ -1330,6 +1330,7 @@ bool multi_delete::send_eof() thd->clear_error(); else errcode= query_error_code(thd, killed_status == NOT_KILLED); + thd->thread_specific_used= TRUE; if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, FALSE, errcode) && diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index e2e7454803b..bc9567f9c67 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3947,8 +3947,12 @@ void select_insert::abort_result_set() { example), no table will have been opened and therefore 'table' will be NULL. In that case, we still need to execute the rollback and the end of the function. + + If it fail due to inability to insert in multi-table view for example, + table will be assigned with view table structure, but that table will + not be opened really (it is dummy to check fields types & Co). */ - if (table) + if (table && table->file->get_table()) { bool changed, transactional_table; /* diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 53b1dd481c3..a6bc4e171da 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2797,14 +2797,13 @@ void st_select_lex::print_limit(THD *thd, if (item && unit->global_parameters() == this) { Item_subselect::subs_type subs_type= item->substype(); - if (subs_type == Item_subselect::EXISTS_SUBS || - subs_type == Item_subselect::IN_SUBS || + if (subs_type == Item_subselect::IN_SUBS || subs_type == Item_subselect::ALL_SUBS) { return; } } - if (explicit_limit) + if (explicit_limit && select_limit) { str->append(STRING_WITH_LEN(" limit ")); if (offset_limit) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 9a49e4024fe..65bce5d2579 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, MariaDB Corporation +/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. + Copyright (c) 2010, 2019, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1023,6 +1023,8 @@ public: TABLE_LIST *end_nested_join(THD *thd); TABLE_LIST *nest_last_join(THD *thd); void add_joined_table(TABLE_LIST *table); + bool add_cross_joined_table(TABLE_LIST *left_op, TABLE_LIST *right_op, + bool straight_fl); TABLE_LIST *convert_right_join(); List<Item>* get_item_list(); ulong get_table_join_options(); @@ -3040,9 +3042,9 @@ public: return context_stack.push_front(context, mem_root); } - void pop_context() + Name_resolution_context *pop_context() { - context_stack.pop(); + return context_stack.pop(); } bool copy_db_to(char **p_db, size_t *p_db_length) const; @@ -3260,15 +3262,18 @@ public: class Yacc_state { public: - Yacc_state() - { - reset(); - } + Yacc_state() : yacc_yyss(NULL), yacc_yyvs(NULL) { reset(); } void reset() { - yacc_yyss= NULL; - yacc_yyvs= NULL; + if (yacc_yyss != NULL) { + my_free(yacc_yyss); + yacc_yyss = NULL; + } + if (yacc_yyvs != NULL) { + my_free(yacc_yyvs); + yacc_yyvs = NULL; + } m_set_signal_info.clear(); m_lock_type= TL_READ_DEFAULT; m_mdl_type= MDL_SHARED_READ; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6e2c38ad053..bc3cd4c2bfd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -8123,6 +8123,7 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd) join_list= ptr->join_list; embedding= ptr->embedding; nested_join= ptr->nested_join; + nested_join->nest_type= 0; if (nested_join->join_list.elements == 1) { TABLE_LIST *embedded= nested_join->join_list.head(); @@ -8132,6 +8133,8 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd) join_list->push_front(embedded, thd->mem_root); ptr= embedded; embedded->lifted= 1; + if (embedded->nested_join) + embedded->nested_join->nest_type= 0; } else if (nested_join->join_list.elements == 0) { @@ -8162,6 +8165,16 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) List<TABLE_LIST> *embedded_list; DBUG_ENTER("nest_last_join"); + TABLE_LIST *head= join_list->head(); + if (head->nested_join && head->nested_join->nest_type & REBALANCED_NEST) + { + List_iterator<TABLE_LIST> li(*join_list); + li++; + while (li++) + li.remove(); + DBUG_RETURN(head); + } + if (!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ sizeof(NESTED_JOIN)))) DBUG_RETURN(0); @@ -8173,6 +8186,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) ptr->alias= (char*) "(nest_last_join)"; embedded_list= &nested_join->join_list; embedded_list->empty(); + nested_join->nest_type= JOIN_OP_NEST; for (uint i=0; i < 2; i++) { @@ -8224,6 +8238,227 @@ void st_select_lex::add_joined_table(TABLE_LIST *table) /** + @brief + Create a node for JOIN/INNER JOIN/CROSS JOIN/STRAIGHT_JOIN operation + + @param left_op the node for the left operand constructed by the parser + @param right_op the node for the right operand constructed by the parser + @param straight_fl TRUE if STRAIGHT_JOIN is used + + @retval + false on success + true otherwise + + @details + + JOIN operator can be left-associative with other join operators in one + context and right-associative in another context. + + In this query + SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a (Q1) + JOIN is left-associative and the query Q1 is interpreted as + SELECT * FROM (t1 JOIN t2) LEFT JOIN t3 ON t2.a=t3.a. + While in this query + SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a ON t1.b=t2.b (Q2) + JOIN is right-associative and the query Q2 is interpreted as + SELECT * FROM t1 JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) ON t1.b=t2.b + + JOIN is right-associative if it is used with ON clause or with USING clause. + Otherwise it is left-associative. + When parsing a join expression with JOIN operator we can't determine + whether this operation left or right associative until either we read the + corresponding ON clause or we reach the end of the expression. This creates + a problem for the parser to build a proper internal representation of the + used join expression. + + For Q1 and Q2 the trees representing the used join expressions look like + + LJ - ON J - ON + / \ / \ + J t3 (TQ1) t1 LJ - ON (TQ2) + / \ / \ + t1 t2 t2 t3 + + To build TQ1 the parser has to reduce the expression for JOIN right after + it has read the reference to t2. To build TQ2 the parser reduces JOIN + when he has read the whole join expression. There is no way to determine + whether an early reduction is needed until the whole join expression is + read. + A solution here is always to do a late reduction. In this case the parser + first builds an incorrect tree TQ1* that has to be rebalanced right after + it has been constructed. + + J LJ - ON + / \ / \ + t1 LJ - ON (TQ1*) => J t3 + / \ / \ + t2 t3 t1 t2 + + Actually the transformation is performed over the nodes t1 and LJ before the + node for J is created in the function st_select_lex::add_cross_joined_table. + The function creates a node for J which replaces the node t2. Then it + attaches the nodes t1 and t2 to this newly created node. The node LJ becomes + the top node of the tree. + + For the query + SELECT * FROM t1 JOIN t2 RIGHT JOIN t3 ON t2.a=t3.a (Q3) + the transformation looks slightly differently because the parser + replaces the RIGHT JOIN tree for an equivalent LEFT JOIN tree. + + J LJ - ON + / \ / \ + t1 LJ - ON (TQ3*) => J t2 + / \ / \ + t3 t2 t1 t3 + + With several left associative JOINs + SELECT * FROM t1 JOIN t2 JOIN t3 LEFT JOIN t4 ON t3.a=t4.a (Q4) + the newly created node for JOIN replaces the left most node of the tree: + + J1 LJ - ON + / \ / \ + t1 LJ - ON J2 t4 + / \ => / \ + J2 t4 J1 t3 + / \ / \ + t2 t3 t1 t2 + + Here's another example: + SELECT * + FROM t1 JOIN t2 LEFT JOIN t3 JOIN t4 ON t3.a=t4.a ON t2.b=t3.b (Q5) + + J LJ - ON + / \ / \ + t1 LJ - ON J J - ON + / \ => / \ / \ + t2 J - ON t1 t2 t3 t4 + / \ + t3 t4 + + If the transformed nested join node node is a natural join node like in + the following query + SELECT * FROM t1 JOIN t2 LEFT JOIN t3 USING(a) (Q6) + the transformation additionally has to take care about setting proper + references in the field natural_join for both operands of the natural + join operation. + The function also has to change the name resolution context for ON + expressions used in the transformed join expression to take into + account the tables of the left_op node. +*/ + +bool st_select_lex::add_cross_joined_table(TABLE_LIST *left_op, + TABLE_LIST *right_op, + bool straight_fl) +{ + DBUG_ENTER("add_cross_joined_table"); + THD *thd= parent_lex->thd; + if (!(right_op->nested_join && + (right_op->nested_join->nest_type & JOIN_OP_NEST))) + { + /* + This handles the cases when the right operand is not a nested join. + like in queries + SELECT * FROM t1 JOIN t2; + SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.a JOIN t3 + */ + right_op->straight= straight_fl; + DBUG_RETURN(false); + } + + TABLE_LIST *tbl; + List<TABLE_LIST> *jl= &right_op->nested_join->join_list; + TABLE_LIST *cj_nest; + + /* + Create the node NJ for a new nested join for the future inclusion + of left_op in it. Initially the nest is empty. + */ + if (unlikely(!(cj_nest= + (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ + sizeof(NESTED_JOIN))))) + DBUG_RETURN(true); + cj_nest->nested_join= + ((NESTED_JOIN*) ((uchar*) cj_nest + ALIGN_SIZE(sizeof(TABLE_LIST)))); + cj_nest->nested_join->nest_type= JOIN_OP_NEST; + List<TABLE_LIST> *cjl= &cj_nest->nested_join->join_list; + cjl->empty(); + + /* Look for the left most node tbl of the right_op tree */ + for ( ; ; ) + { + TABLE_LIST *pair_tbl= 0; /* useful only for operands of natural joins */ + + List_iterator<TABLE_LIST> li(*jl); + tbl= li++; + + /* Expand name resolution context */ + Name_resolution_context *on_context; + if ((on_context= tbl->on_context)) + { + on_context->first_name_resolution_table= + left_op->first_leaf_for_name_resolution(); + } + + if (!(tbl->outer_join & JOIN_TYPE_RIGHT)) + { + pair_tbl= tbl; + tbl= li++; + } + if (tbl->nested_join && + tbl->nested_join->nest_type & JOIN_OP_NEST) + { + jl= &tbl->nested_join->join_list; + continue; + } + + /* Replace the tbl node in the tree for the newly created NJ node */ + cj_nest->outer_join= tbl->outer_join; + cj_nest->on_expr= tbl->on_expr; + cj_nest->embedding= tbl->embedding; + cj_nest->join_list= jl; + cj_nest->alias= (char*) "(nest_last_join)"; + li.replace(cj_nest); + + /* + If tbl is an operand of a natural join set properly the references + in the fields natural_join for both operands of the operation. + */ + if(tbl->embedding && tbl->embedding->is_natural_join) + { + if (!pair_tbl) + pair_tbl= li++; + pair_tbl->natural_join= cj_nest; + cj_nest->natural_join= pair_tbl; + } + break; + } + + /* Attach tbl as the right operand of NJ */ + if (unlikely(cjl->push_back(tbl, thd->mem_root))) + DBUG_RETURN(true); + tbl->outer_join= 0; + tbl->on_expr= 0; + tbl->straight= straight_fl; + tbl->natural_join= 0; + tbl->embedding= cj_nest; + tbl->join_list= cjl; + + /* Add left_op as the left operand of NJ */ + if (unlikely(cjl->push_back(left_op, thd->mem_root))) + DBUG_RETURN(true); + left_op->embedding= cj_nest; + left_op->join_list= cjl; + + /* + Mark right_op as a rebalanced nested join in order not to + create a new top level nested join node. + */ + right_op->nested_join->nest_type|= REBALANCED_NEST; + DBUG_RETURN(false); +} + + +/** Convert a right join into equivalent left join. The function takes the current join list t[0],t[1] ... and diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 19c0f508939..44b2a8220b3 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -748,9 +748,9 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) This is done to ensure that only approved libraries from the plugin directory are used (to make this even remotely secure). */ - if (check_valid_path(dl->str, dl->length) || - check_string_char_length((LEX_STRING *) dl, 0, NAME_CHAR_LEN, + if (check_string_char_length((LEX_STRING *) dl, 0, NAME_CHAR_LEN, system_charset_info, 1) || + check_valid_path(dl->str, dl->length) || plugin_dir_len + dl->length + 1 >= FN_REFLEN) { report_error(report, ER_UDF_NO_PATHS); @@ -1826,6 +1826,9 @@ static void plugin_load(MEM_ROOT *tmp_root) LEX_STRING name= {(char *)str_name.ptr(), str_name.length()}; LEX_STRING dl= {(char *)str_dl.ptr(), str_dl.length()}; + if (!name.length || !dl.length) + continue; + /* there're no other threads running yet, so we don't need a mutex. but plugin_add() before is designed to work in multi-threaded diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a1685508d18..bdab9cf76cf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1262,7 +1262,6 @@ JOIN::optimize_inner() DBUG_RETURN(1); /* purecov: inspected */ /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */ select_lex->update_used_tables(); - } eval_select_list_used_tables(); @@ -1332,6 +1331,8 @@ JOIN::optimize_inner() sel->where= conds; + select_lex->update_used_tables(); + if (arena) thd->restore_active_arena(arena, &backup); } @@ -13074,6 +13075,9 @@ static bool check_simple_equality(THD *thd, const Item::Context &ctx, { if (((Item_ref*)left_item)->get_depended_from()) return FALSE; + if (((Item_direct_view_ref*)left_item)->get_null_ref_table() != + NO_NULL_TABLE && !left_item->real_item()->used_tables()) + return FALSE; left_item= left_item->real_item(); } if (right_item->type() == Item::REF_ITEM && @@ -13081,6 +13085,9 @@ static bool check_simple_equality(THD *thd, const Item::Context &ctx, { if (((Item_ref*)right_item)->get_depended_from()) return FALSE; + if (((Item_direct_view_ref*)right_item)->get_null_ref_table() != + NO_NULL_TABLE && !right_item->real_item()->used_tables()) + return FALSE; right_item= right_item->real_item(); } if (left_item->type() == Item::FIELD_ITEM && diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bbc8cc4be01..fbd6622b1b2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2016, Oracle and/or its affiliates. + Copyright (c) 2000, 2019, Oracle and/or its affiliates. Copyright (c) 2010, 2019, MariaDB This program is free software; you can redistribute it and/or modify @@ -2522,8 +2522,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, table->table ? table->table->s : NULL)); } DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog"); - thd->thread_specific_used|= (trans_tmp_table_deleted || - non_trans_tmp_table_deleted); + thd->thread_specific_used= TRUE; error= 0; err: if (wrong_tables.length()) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 90acbb94f8c..b5cece45148 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1025,7 +1025,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); Currently there are 102 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 102 +%expect 101 /* Comments for TOKENS. @@ -1714,9 +1714,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token IMPOSSIBLE_ACTION /* To avoid warning for yyerrlab1 */ -%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT /* A dummy token to force the priority of table_ref production in a join. */ -%left TABLE_REF_PRIORITY +%left CONDITIONLESS_JOIN +%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT ON_SYM USING %left SET_VAR %left OR_OR_SYM OR_SYM OR2_SYM %left XOR @@ -10817,9 +10817,9 @@ join_table_list: and are ignored. */ esc_table_ref: - table_ref { $$=$1; } - | '{' ident table_ref '}' { $$=$3; } - ; + table_ref { $$=$1; } + | '{' ident table_ref '}' { $$=$3; } + ; /* Equivalent to <table reference list> in the SQL:2003 standard. */ /* Warning - may return NULL in case of incomplete SELECT */ @@ -10832,11 +10832,9 @@ derived_table_list: ; /* - Notice that JOIN is a left-associative operation, and it must be parsed - as such, that is, the parser must process first the left join operand - then the right one. Such order of processing ensures that the parser - produces correct join trees which is essential for semantic analysis - and subsequent optimization phases. + Notice that JOIN can be a left-associative operator in one context and + a right-associative operator in another context (see the comment for + st_select_lex::add_cross_joined_table). */ join_table: /* INNER JOIN variants */ @@ -10845,8 +10843,13 @@ join_table: so that [INNER | CROSS] JOIN is properly nested as other left-associative joins. */ - table_ref normal_join table_ref %prec TABLE_REF_PRIORITY - { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=$2; } + table_ref normal_join table_ref %prec CONDITIONLESS_JOIN + { + MYSQL_YYABORT_UNLESS($1 && ($$=$3)); + + if (unlikely(Select->add_cross_joined_table($1, $3, $2))) + MYSQL_YYABORT; + } | table_ref normal_join table_ref ON { @@ -10860,7 +10863,7 @@ join_table: { $3->straight=$2; add_join_on(thd, $3, $6); - Lex->pop_context(); + $3->on_context= Lex->pop_context(); Select->parsing_place= NO_MATTER; } | table_ref normal_join table_ref @@ -10894,7 +10897,7 @@ join_table: expr { add_join_on(thd, $5, $8); - Lex->pop_context(); + $5->on_context= Lex->pop_context(); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; Select->parsing_place= NO_MATTER; @@ -10933,7 +10936,7 @@ join_table: if (!($$= lex->current_select->convert_right_join())) MYSQL_YYABORT; add_join_on(thd, $$, $8); - Lex->pop_context(); + $1->on_context= Lex->pop_context(); Select->parsing_place= NO_MATTER; } | table_ref RIGHT opt_outer JOIN_SYM table_factor diff --git a/sql/table.h b/sql/table.h index 444e1c5f00f..7786679982f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -54,6 +54,7 @@ struct TDC_element; class Virtual_column_info; class Table_triggers_list; class TMP_TABLE_PARAM; +struct Name_resolution_context; /* Used to identify NESTED_JOIN structures within a join (applicable only to @@ -1819,6 +1820,7 @@ struct TABLE_LIST char *db, *alias, *table_name, *schema_table_name; char *option; /* Used by cache index */ Item *on_expr; /* Used with outer join */ + Name_resolution_context *on_context; /* For ON expressions */ Item *sj_on_expr; /* @@ -2563,9 +2565,31 @@ public: }; +#define JOIN_OP_NEST 1 +#define REBALANCED_NEST 2 + typedef struct st_nested_join { List<TABLE_LIST> join_list; /* list of elements in the nested join */ + /* + Currently the valid values for nest type are: + JOIN_OP_NEST - for nest created for JOIN operation used as an operand in + a join expression, contains 2 elements; + JOIN_OP_NEST | REBALANCED_NEST - nest created after tree re-balancing + in st_select_lex::add_cross_joined_table(), contains 1 element; + 0 - for all other nests. + Examples: + 1. SELECT * FROM t1 JOIN t2 LEFT JOIN t3 ON t2.a=t3.a; + Here the nest created for LEFT JOIN at first has nest_type==JOIN_OP_NEST. + After re-balancing in st_select_lex::add_cross_joined_table() this nest + has nest_type==JOIN_OP_NEST | REBALANCED_NEST. The nest for JOIN created + in st_select_lex::add_cross_joined_table() has nest_type== JOIN_OP_NEST. + 2. SELECT * FROM t1 JOIN (t2 LEFT JOIN t3 ON t2.a=t3.a) + Here the nest created for LEFT JOIN has nest_type==0, because it's not + an operand in a join expression. The nest created for JOIN has nest_type + set to JOIN_OP_NEST. + */ + uint nest_type; /* Bitmap of tables within this nested join (including those embedded within its children), including tables removed by table elimination. |