mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 04:22:27 +01:00
7517d7e112
"Process NATURAL and USING joins according to SQL:2003". * Some of the main problems fixed by the patch: - in "select *" queries the * expanded correctly according to ANSI for arbitrary natural/using joins - natural/using joins are correctly transformed into JOIN ... ON for any number/nesting of the joins. - column references are correctly resolved against natural joins of any nesting and combined with arbitrary other joins. * This patch also contains a fix for name resolution of items inside the ON condition of JOIN ... ON - in this case items must be resolved only against the JOIN operands. To support such 'local' name resolution, the patch introduces a stack of name resolution contexts used at parse time. NOTICE: - This patch is not complete in the sense that - there are 2 test cases that still do not pass - one in join.test, one in select.test. Both are marked with a comment "TODO: WL#2486". - it does not include a new test specific for the task mysql-test/include/ps_query.inc: Adjusted according to standard NATURAL/USING join semantics., mysql-test/r/bdb.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/derived.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/errors.result: The column as a whole cannot be resolved, so different error message. mysql-test/r/fulltext.result: Adjusted according to standard JOIN ... ON semantics => the ON condition can refer only to the join operands. mysql-test/r/fulltext_order_by.result: More detailed error message. mysql-test/r/innodb.result: Adjusted according to standard NATURAL/USING join semantics. This test doesn't pass completetly yet! mysql-test/r/insert_select.result: More detailed error message. mysql-test/r/join.result: Adjusted according to standard NATURAL/USING join semantics. NOTICE: there is one test case that still fails, and it is commeted out and marked with WL#2486 in the test file. mysql-test/r/join_crash.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/join_nested.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/join_outer.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/multi_update.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/null_key.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/order_by.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/ps_2myisam.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/ps_3innodb.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/ps_4heap.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/ps_5merge.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/ps_6bdb.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/ps_7ndb.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/select.result: Adjusted according to standard NATURAL/USING join semantics. NOTICE: there is one failing test case which is commented with WL#2486 in the test file. mysql-test/r/subselect.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/type_ranges.result: Adjusted according to standard NATURAL/USING join semantics. mysql-test/r/union.result: More detailed error message. mysql-test/t/bdb.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/errors.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/fulltext.test: Adjusted according to standard JOIN ... ON semantics => the ON condition can refer only to the join operands. mysql-test/t/fulltext_order_by.test: More detailed error message. mysql-test/t/innodb.test: Adjusted according to standard NATURAL/USING join semantics. This test doesn't pass completetly yet! mysql-test/t/insert_select.test: More detailed error message. mysql-test/t/join.test: Adjusted according to standard NATURAL/USING join semantics. NOTICE: there is one test case that still fails, and it is commeted out and marked with WL#2486 in the test file. mysql-test/t/join_crash.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/join_nested.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/join_outer.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/null_key.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/order_by.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/select.test: Adjusted according to standard NATURAL/USING join semantics. NOTICE: there is one test case that still fails, and it is commeted out and marked with WL#2486 in the test file. mysql-test/t/subselect.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/type_ranges.test: Adjusted according to standard NATURAL/USING join semantics. mysql-test/t/union.test: More detailed error message. sql/item.cc: - extra parameter to find_field_in_tables - find_field_in_real_table renamed to find_field_in_table - fixed comments/typos sql/item.h: - added [first | last]_name_resolution_table to class Name_resolution_context - commented old code - standardized formatting sql/mysql_priv.h: - refactored the find_field_in_XXX procedures, - added a new procedure for natural join table references, - renamed the find_field_in_XXX procedures to clearer names sql/sp.cc: - pass the top-most list of the FROM clause to setup_tables - extra parameter to find_field_in_tables sql/sql_acl.cc: - renamed find_field_in_table => find_field_in_table_ref - extra parameter to find_field_in_table_ref - commented old code sql/sql_base.cc: This file contains the core of the implementation of the processing of NATURAL/USING joins (WL#2486). - added many comments to old code - refactored the group of find_field_in_XXX procedures, and added a new procedure for natural joins. There is one find_field_in_XXX procedure per each type of table reference (stored table, merge view, or natural join); one meta-procedure that selects the correct one depeneding on the table reference; and one procedure that goes over a list of table referenes. - NATURAL/USING joins are processed through the procedures: mark_common_columns, store_natural_using_join_columns, store_top_level_join_columns, setup_natural_join_row_types. The entry point to processing NATURAL/USING joins is the procedure 'setup_natural_join_row_types'. - Replaced the specialized Field_iterator_XXX iterators with one generic iterator over the fields of a table reference. - Simplified 'insert_fields' and 'setup_conds' due to encapsulation of the processing of natural joins in a separate set of procedures. sql/sql_class.h: - Commented old code. sql/sql_delete.cc: - Pass the FROM clause to setup_tables. sql/sql_help.cc: - pass the end name resolution table to find_field_in_tables - adjust the list of tables for name resolution sql/sql_insert.cc: - Changed the code that saves and restores the current context to support the list of tables for name resolution - context->first_name_resolution_table, and table_list->next_name_resolution_table. Needed to support an ugly trick to resolve inserted columns only in the first table. - Added Name_resolution_context::[first | last]_name_resolution_table. - Commented old code sql/sql_lex.cc: - set select_lex.parent_lex correctly - set correct state of the current name resolution context sql/sql_lex.h: - Added a stack of name resolution contexts to support local contexts for JOIN ... ON conditions. - Commented old code. sql/sql_load.cc: - Pass the FROM clause to setup_tables. sql/sql_olap.cc: - Pass the FROM clause to setup_tables. sql/sql_parse.cc: - correctly set SELECT_LEX::parent_lex - set the first table of the current name resoltion context - added support for NATURAL/USING joins - commented old code sql/sql_select.cc: - Pass the FROM clause to setup_tables. - Pass the end table to find_field_in_tables - Improved comments sql/sql_show.cc: - Set SELECT_LEX::parent_lex. sql/sql_update.cc: - Pass the FROM clause to setup_tables. sql/sql_yacc.yy: - Added support for a stack of name resolution contexts needed to implement name resolution for JOIN ... ON. A context is pushed for each new JOIN ... ON, and popped afterwards. - Added support for NATURAL/USING joins. sql/table.cc: - Added new class Natural_join_column to hide the heterogeneous representation of column references for stored tables and for views. - Added a new list TABLE_LIST::next_name_resolution_table to support name resolution with NATURAL/USING joins. Also added other members to TABLE_LIST to support NATURAL/USING joins. - Added a generic iterator over the fields of table references of various types - class Field_iterator_table_ref sql/table.h: - Added new class Natural_join_column to hide the heterogeneous representation of column references for stored tables and for views. - Added a new list TABLE_LIST::next_name_resolution_table to support name resolution with NATURAL/USING joins. Also added other members to TABLE_LIST to support NATURAL/USING joins. - Added a generic iterator over the fields of table references of various types - class Field_iterator_table_ref tests/mysql_client_test.c: Adjusted according to standard NATURAL JOIN syntax.
186 lines
6 KiB
C++
186 lines
6 KiB
C++
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
|
|
|
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
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
/*
|
|
OLAP implementation by Sinisa Milivojevic <sinisa@mysql.com>
|
|
Inspired by code submitted by Srilakshmi <lakshmi@gdit.iiit.net>
|
|
|
|
The ROLLUP code in this file has to be complitely rewritten as it's
|
|
not good enough to satisfy the goals of MySQL.
|
|
|
|
In 4.1 we will replace this with a working, superior implementation
|
|
of ROLLUP.
|
|
*/
|
|
|
|
#ifdef DISABLED_UNTIL_REWRITTEN_IN_4_1
|
|
|
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
|
#pragma implementation // gcc: Class implementation
|
|
#endif
|
|
|
|
#include "mysql_priv.h"
|
|
#include "sql_select.h"
|
|
|
|
|
|
/****************************************************************************
|
|
Functions that recursively actually creates new SELECT's
|
|
Returns 0 if OK, 1 if error, -1 if error already printed to client
|
|
****************************************************************************/
|
|
|
|
|
|
static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new_fields)
|
|
{
|
|
THD *thd=current_thd;
|
|
Item *item, *new_item;
|
|
Item_null *constant= new Item_null("ALL");
|
|
|
|
SELECT_LEX *new_select = (SELECT_LEX *) thd->memdup((char*) select_lex, sizeof(*select_lex));
|
|
if (!new_select)
|
|
return 1;
|
|
lex->last_selects->next=new_select;
|
|
new_select->linkage=OLAP_TYPE;
|
|
new_select->olap=NON_EXISTING_ONE;
|
|
new_select->group_list.elements=0;
|
|
new_select->group_list.first=(byte *)0;
|
|
new_select->group_list.next=(byte **)&new_select->group_list.first;
|
|
List<Item> privlist;
|
|
|
|
List_iterator<Item> list_it(select_lex->item_list);
|
|
List_iterator<Item> new_it(new_fields);
|
|
|
|
while ((item=list_it++))
|
|
{
|
|
bool not_found= TRUE;
|
|
if (item->type()==Item::FIELD_ITEM)
|
|
{
|
|
Item_field *iif = (Item_field *)item;
|
|
new_it.rewind();
|
|
while ((new_item=new_it++))
|
|
{
|
|
if (new_item->type()==Item::FIELD_ITEM &&
|
|
!strcmp(((Item_field*)new_item)->table_name,iif->table_name) &&
|
|
!strcmp(((Item_field*)new_item)->field_name,iif->field_name))
|
|
{
|
|
not_found= 0;
|
|
((Item_field*)new_item)->db_name=iif->db_name;
|
|
Item_field *new_one=new Item_field(&select_lex->context,
|
|
iif->db_name, iif->table_name, iif->field_name);
|
|
privlist.push_back(new_one);
|
|
if (add_to_list(new_select->group_list,new_one,1))
|
|
return 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (not_found)
|
|
{
|
|
if (item->type() == Item::FIELD_ITEM)
|
|
privlist.push_back(constant);
|
|
else
|
|
privlist.push_back((Item*)thd->memdup((char *)item,item->size_of()));
|
|
}
|
|
}
|
|
new_select->item_list=privlist;
|
|
|
|
lex->last_selects = new_select;
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Functions that recursively creates combinations of queries for OLAP
|
|
Returns 0 if OK, 1 if error, -1 if error already printed to client
|
|
****************************************************************************/
|
|
|
|
static int olap_combos(List<Item> old_fields, List<Item> new_fields, Item *item, LEX *lex,
|
|
SELECT_LEX *select_lex, int position, int selection, int num_fields,
|
|
int num_new_fields)
|
|
{
|
|
int sl_return = 0;
|
|
if (position == num_new_fields)
|
|
{
|
|
if (item)
|
|
new_fields.push_front(item);
|
|
sl_return = make_new_olap_select(lex, select_lex, new_fields);
|
|
}
|
|
else
|
|
{
|
|
if (item)
|
|
new_fields.push_front(item);
|
|
while ((num_fields - num_new_fields >= selection - position) && !sl_return)
|
|
{
|
|
item = old_fields.pop();
|
|
sl_return = olap_combos(old_fields, new_fields, item, lex, select_lex, position+1, ++selection, num_fields, num_new_fields);
|
|
}
|
|
}
|
|
return sl_return;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Top level function for converting OLAP clauses to multiple selects
|
|
This is also a place where clauses treatment depends on OLAP type
|
|
Returns 0 if OK, 1 if error, -1 if error already printed to client
|
|
****************************************************************************/
|
|
|
|
int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
|
|
{
|
|
List<Item> item_list_copy, new_item_list;
|
|
item_list_copy.empty();
|
|
new_item_list.empty();
|
|
int count=select_lex->group_list.elements;
|
|
int sl_return=0;
|
|
|
|
|
|
lex->last_selects=select_lex;
|
|
|
|
for (ORDER *order=(ORDER *)select_lex->group_list.first ; order ; order=order->next)
|
|
item_list_copy.push_back(*(order->item));
|
|
|
|
List<Item> all_fields(select_lex->item_list);
|
|
|
|
|
|
if (setup_tables(lex->thd, &select_lex->context, &select_lex->top_join_list,
|
|
(TABLE_LIST *)select_lex->table_list.first
|
|
&select_lex->where, &select_lex->leaf_tables, FALSE) ||
|
|
setup_fields(lex->thd, 0, select_lex->item_list, 1, &all_fields,1) ||
|
|
setup_fields(lex->thd, 0, item_list_copy, 1, &all_fields, 1))
|
|
return -1;
|
|
|
|
if (select_lex->olap == CUBE_TYPE)
|
|
{
|
|
for ( int i=count-1; i>=0 && !sl_return; i--)
|
|
sl_return=olap_combos(item_list_copy, new_item_list, (Item *)0, lex, select_lex, 0, 0, count, i);
|
|
}
|
|
else if (select_lex->olap == ROLLUP_TYPE)
|
|
{
|
|
for ( int i=count-1; i>=0 && !sl_return; i--)
|
|
{
|
|
Item *item;
|
|
item_list_copy.pop();
|
|
List_iterator<Item> it(item_list_copy);
|
|
new_item_list.empty();
|
|
while ((item = it++))
|
|
new_item_list.push_front(item);
|
|
sl_return=make_new_olap_select(lex, select_lex, new_item_list);
|
|
}
|
|
}
|
|
else
|
|
sl_return=1; // impossible
|
|
return sl_return;
|
|
}
|
|
|
|
#endif /* DISABLED_UNTIL_REWRITTEN_IN_4_1 */
|